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.

930 lines
26 KiB

  1. /*++
  2. Copyright (c) 1989-1993 Microsoft Corporation
  3. Module Name:
  4. frame.c
  5. Abstract:
  6. This module contains code which creates and sends various
  7. types of frames.
  8. Environment:
  9. Kernel mode
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. VOID
  15. NbiSendNameFrame(
  16. IN PADDRESS Address OPTIONAL,
  17. IN UCHAR NameTypeFlag,
  18. IN UCHAR DataStreamType,
  19. IN PIPX_LOCAL_TARGET LocalTarget OPTIONAL,
  20. IN NB_CONNECTIONLESS UNALIGNED * ReqFrame OPTIONAL
  21. )
  22. /*++
  23. Routine Description:
  24. This routine allocates and sends a name frame on the
  25. specified address. It handles add name, name in use, and
  26. delete name frames.
  27. Arguments:
  28. Address - The address on which the frame is sent. This will
  29. be NULL if we are responding to a request to the
  30. broadcast address.
  31. NameTypeFlag - The name type flag to use.
  32. DataStreamType - The type of the command.
  33. LocalTarget - If specified, the local target to use for the
  34. send (if not, it will be broadcast).
  35. ReqFrame - If specified, the request frame for which this
  36. response is being sent. The reqframe contains the
  37. destination ipx address and the netbios name.
  38. Return Value:
  39. None.
  40. --*/
  41. {
  42. PSINGLE_LIST_ENTRY s;
  43. PNB_SEND_RESERVED Reserved;
  44. PNDIS_PACKET Packet;
  45. NB_CONNECTIONLESS UNALIGNED * Header;
  46. NDIS_STATUS NdisStatus;
  47. IPX_LOCAL_TARGET TempLocalTarget;
  48. PDEVICE Device = NbiDevice;
  49. //
  50. // Allocate a packet from the pool.
  51. //
  52. s = NbiPopSendPacket(Device, FALSE);
  53. //
  54. // If we can't allocate a frame, that is OK, since
  55. // it is connectionless anyway.
  56. //
  57. if (s == NULL) {
  58. return;
  59. }
  60. Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
  61. Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
  62. CTEAssert (Reserved->SendInProgress == FALSE);
  63. Reserved->SendInProgress = TRUE;
  64. Reserved->u.SR_NF.Address = Address; // may be NULL
  65. Reserved->Type = SEND_TYPE_NAME_FRAME;
  66. //
  67. // Frame that are not sent to a specific address are
  68. // sent to all valid NIC IDs.
  69. //
  70. if (!ARGUMENT_PRESENT(LocalTarget)) {
  71. Reserved->u.SR_NF.NameTypeFlag = NameTypeFlag;
  72. Reserved->u.SR_NF.DataStreamType = DataStreamType;
  73. }
  74. //
  75. // Fill in the IPX header -- the default header has the broadcast
  76. // address on net 0 as the destination IPX address.
  77. //
  78. Header = (NB_CONNECTIONLESS UNALIGNED *)
  79. (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
  80. RtlCopyMemory((PVOID)&Header->IpxHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
  81. if (ARGUMENT_PRESENT(ReqFrame)) {
  82. RtlCopyMemory((PVOID)&Header->IpxHeader.DestinationNetwork, (PVOID)ReqFrame->IpxHeader.SourceNetwork, 12);
  83. }
  84. Header->IpxHeader.PacketLength[0] = (sizeof(IPX_HEADER)+sizeof(NB_NAME_FRAME)) / 256;
  85. Header->IpxHeader.PacketLength[1] = (sizeof(IPX_HEADER)+sizeof(NB_NAME_FRAME)) % 256;
  86. if (ARGUMENT_PRESENT(LocalTarget)) {
  87. Header->IpxHeader.PacketType = 0x04;
  88. } else {
  89. Header->IpxHeader.PacketType = (UCHAR)(Device->Internet ? 0x014 : 0x04);
  90. }
  91. //
  92. // Now fill in the Netbios header.
  93. //
  94. RtlZeroMemory (Header->NameFrame.RoutingInfo, 32);
  95. Header->NameFrame.ConnectionControlFlag = 0x00;
  96. Header->NameFrame.DataStreamType = DataStreamType;
  97. Header->NameFrame.NameTypeFlag = NameTypeFlag;
  98. //
  99. // DataStreamType2 is the same as DataStreamType except for
  100. // name in use frames where it is set to the add name type.
  101. //
  102. Header->NameFrame.DataStreamType2 = (UCHAR)
  103. ((DataStreamType != NB_CMD_NAME_IN_USE) ? DataStreamType : NB_CMD_ADD_NAME);
  104. RtlCopyMemory(
  105. Header->NameFrame.Name,
  106. Address ? Address->NetbiosAddress.NetbiosName : ReqFrame->NameFrame.Name,
  107. 16);
  108. if (Address) {
  109. NbiReferenceAddress (Address, AREF_NAME_FRAME);
  110. } else {
  111. NbiReferenceDevice (Device, DREF_NAME_FRAME);
  112. }
  113. //
  114. // Now send the frame (because it is all in the first segment,
  115. // IPX will adjust the length of the buffer correctly).
  116. //
  117. if (!ARGUMENT_PRESENT(LocalTarget)) {
  118. LocalTarget = &BroadcastTarget;
  119. }
  120. NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(IPX_HEADER) +
  121. sizeof(NB_NAME_FRAME));
  122. if ((NdisStatus =
  123. (*Device->Bind.SendHandler)(
  124. LocalTarget,
  125. Packet,
  126. sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME),
  127. sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME))) != STATUS_PENDING) {
  128. NbiSendComplete(
  129. Packet,
  130. NdisStatus);
  131. }
  132. } /* NbiSendNameFrame */
  133. VOID
  134. NbiSendSessionInitialize(
  135. IN PCONNECTION Connection
  136. )
  137. /*++
  138. Routine Description:
  139. This routine allocates and sends a session initialize
  140. frame for the specified connection.
  141. Arguments:
  142. Connection - The connection on which the frame is sent.
  143. Return Value:
  144. None.
  145. --*/
  146. {
  147. PSINGLE_LIST_ENTRY s;
  148. PNB_SEND_RESERVED Reserved;
  149. PNDIS_PACKET Packet;
  150. NB_CONNECTION UNALIGNED * Header;
  151. NDIS_STATUS NdisStatus;
  152. PNB_SESSION_INIT SessionInitMemory;
  153. PNDIS_BUFFER SessionInitBuffer;
  154. PDEVICE Device = NbiDevice;
  155. //
  156. // Allocate a packet from the pool.
  157. //
  158. s = NbiPopSendPacket(Device, FALSE);
  159. //
  160. // If we can't allocate a frame, that is OK, since
  161. // it is connectionless anyway.
  162. //
  163. if (s == NULL) {
  164. return;
  165. }
  166. //
  167. // Allocate a buffer for the extra portion of the
  168. // session initialize.
  169. //
  170. SessionInitMemory = (PNB_SESSION_INIT)NbiAllocateMemory(sizeof(NB_SESSION_INIT), MEMORY_CONNECTION, "Session Initialize");
  171. if (!SessionInitMemory) {
  172. ExInterlockedPushEntrySList(
  173. &Device->SendPacketList,
  174. s,
  175. &NbiGlobalPoolInterlock);
  176. return;
  177. }
  178. //
  179. // Allocate an NDIS buffer to map the extra buffer.
  180. //
  181. NdisAllocateBuffer(
  182. &NdisStatus,
  183. &SessionInitBuffer,
  184. Device->NdisBufferPoolHandle,
  185. SessionInitMemory,
  186. sizeof(NB_SESSION_INIT));
  187. if (NdisStatus != NDIS_STATUS_SUCCESS) {
  188. NbiFreeMemory (SessionInitMemory, sizeof(NB_SESSION_INIT), MEMORY_CONNECTION, "Session Initialize");
  189. ExInterlockedPushEntrySList(
  190. &Device->SendPacketList,
  191. s,
  192. &NbiGlobalPoolInterlock);
  193. return;
  194. }
  195. Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
  196. Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
  197. CTEAssert (Reserved->SendInProgress == FALSE);
  198. Reserved->SendInProgress = TRUE;
  199. Reserved->Type = SEND_TYPE_SESSION_INIT;
  200. //
  201. // Fill in the IPX header -- the default header has the broadcast
  202. // address on net 0 as the destination IPX address.
  203. //
  204. Header = (NB_CONNECTION UNALIGNED *)
  205. (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
  206. RtlCopyMemory((PVOID)&Header->IpxHeader, &Connection->RemoteHeader, sizeof(IPX_HEADER));
  207. Header->IpxHeader.PacketLength[0] = (sizeof(NB_CONNECTION)+sizeof(NB_SESSION_INIT)) / 256;
  208. Header->IpxHeader.PacketLength[1] = (sizeof(NB_CONNECTION)+sizeof(NB_SESSION_INIT)) % 256;
  209. Header->IpxHeader.PacketType = 0x04;
  210. //
  211. // Now fill in the Netbios header.
  212. //
  213. if (Device->Extensions) {
  214. Header->Session.ConnectionControlFlag = NB_CONTROL_SEND_ACK | NB_CONTROL_NEW_NB;
  215. } else {
  216. Header->Session.ConnectionControlFlag = NB_CONTROL_SEND_ACK;
  217. }
  218. Header->Session.DataStreamType = NB_CMD_SESSION_DATA;
  219. Header->Session.SourceConnectionId = Connection->LocalConnectionId;
  220. Header->Session.DestConnectionId = 0xffff;
  221. Header->Session.SendSequence = 0;
  222. Header->Session.TotalDataLength = sizeof(NB_SESSION_INIT);
  223. Header->Session.Offset = 0;
  224. Header->Session.DataLength = sizeof(NB_SESSION_INIT);
  225. Header->Session.ReceiveSequence = 0;
  226. if (Device->Extensions) {
  227. Header->Session.ReceiveSequenceMax = 1; // low estimate for the moment
  228. } else {
  229. Header->Session.BytesReceived = 0;
  230. }
  231. RtlCopyMemory (SessionInitMemory->SourceName, Connection->AddressFile->Address->NetbiosAddress.NetbiosName, 16);
  232. RtlCopyMemory (SessionInitMemory->DestinationName, Connection->RemoteName, 16);
  233. SessionInitMemory->MaximumDataSize = (USHORT)Connection->MaximumPacketSize;
  234. SessionInitMemory->StartTripTime = (USHORT)
  235. ((Device->InitialRetransmissionTime * (Device->KeepAliveCount+1)) / 500);
  236. SessionInitMemory->MaximumPacketTime = SessionInitMemory->StartTripTime + 12;
  237. //
  238. // Should we ref the connection? It doesn't really matter which we do.
  239. //
  240. NbiReferenceDevice (Device, DREF_SESSION_INIT);
  241. NdisChainBufferAtBack (Packet, SessionInitBuffer);
  242. //
  243. // Now send the frame, IPX will adjust the length of the
  244. // first buffer correctly.
  245. //
  246. NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(NB_CONNECTION));
  247. if ((NdisStatus =
  248. (*Device->Bind.SendHandler)(
  249. &Connection->LocalTarget,
  250. Packet,
  251. sizeof(NB_CONNECTION) + sizeof(NB_SESSION_INIT),
  252. sizeof(NB_CONNECTION))) != STATUS_PENDING) {
  253. NbiSendComplete(
  254. Packet,
  255. NdisStatus);
  256. }
  257. } /* NbiSendSessionInitialize */
  258. VOID
  259. NbiSendSessionInitAck(
  260. IN PCONNECTION Connection,
  261. IN PUCHAR ExtraData,
  262. IN ULONG ExtraDataLength,
  263. IN CTELockHandle * LockHandle OPTIONAL
  264. )
  265. /*++
  266. Routine Description:
  267. This routine allocates and sends a session initialize ack
  268. frame for the specified connection. If extra data was
  269. specified in the session initialize frame it is echoed
  270. back to the remote.
  271. Arguments:
  272. Connection - The connection on which the frame is sent.
  273. ExtraData - Any extra data (after the SESSION_INIT buffer)
  274. in the frame.
  275. ExtraDataLength - THe length of the extra data.
  276. LockHandle - If specified, indicates the connection lock
  277. is held and should be released. This is for cases
  278. where the ExtraData is in memory which may be freed
  279. once the connection lock is released.
  280. Return Value:
  281. None.
  282. --*/
  283. {
  284. PSINGLE_LIST_ENTRY s;
  285. PNB_SEND_RESERVED Reserved;
  286. PNDIS_PACKET Packet;
  287. NB_CONNECTION UNALIGNED * Header;
  288. NDIS_STATUS NdisStatus;
  289. ULONG SessionInitBufferLength;
  290. PNB_SESSION_INIT SessionInitMemory;
  291. PNDIS_BUFFER SessionInitBuffer;
  292. PDEVICE Device = NbiDevice;
  293. //
  294. // Allocate a packet from the pool.
  295. //
  296. s = NbiPopSendPacket(Device, FALSE);
  297. //
  298. // If we can't allocate a frame, that is OK, since
  299. // it is connectionless anyway.
  300. //
  301. if (s == NULL) {
  302. if (ARGUMENT_PRESENT(LockHandle)) {
  303. NB_FREE_LOCK (&Connection->Lock, *LockHandle);
  304. }
  305. return;
  306. }
  307. //
  308. // Allocate a buffer for the extra portion of the
  309. // session initialize.
  310. //
  311. SessionInitBufferLength = sizeof(NB_SESSION_INIT) + ExtraDataLength;
  312. SessionInitMemory = (PNB_SESSION_INIT)NbiAllocateMemory(SessionInitBufferLength, MEMORY_CONNECTION, "Session Initialize");
  313. if (!SessionInitMemory) {
  314. ExInterlockedPushEntrySList(
  315. &Device->SendPacketList,
  316. s,
  317. &NbiGlobalPoolInterlock);
  318. if (ARGUMENT_PRESENT(LockHandle)) {
  319. NB_FREE_LOCK (&Connection->Lock, *LockHandle);
  320. }
  321. return;
  322. }
  323. //
  324. // Save the extra data, now we can free the lock.
  325. //
  326. if (ExtraDataLength != 0) {
  327. RtlCopyMemory (SessionInitMemory+1, ExtraData, ExtraDataLength);
  328. }
  329. if (ARGUMENT_PRESENT(LockHandle)) {
  330. NB_FREE_LOCK (&Connection->Lock, *LockHandle);
  331. }
  332. //
  333. // Allocate an NDIS buffer to map the extra buffer.
  334. //
  335. NdisAllocateBuffer(
  336. &NdisStatus,
  337. &SessionInitBuffer,
  338. Device->NdisBufferPoolHandle,
  339. SessionInitMemory,
  340. SessionInitBufferLength);
  341. if (NdisStatus != NDIS_STATUS_SUCCESS) {
  342. NbiFreeMemory (SessionInitMemory, SessionInitBufferLength, MEMORY_CONNECTION, "Session Initialize");
  343. ExInterlockedPushEntrySList(
  344. &Device->SendPacketList,
  345. s,
  346. &NbiGlobalPoolInterlock);
  347. return;
  348. }
  349. Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
  350. Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
  351. CTEAssert (Reserved->SendInProgress == FALSE);
  352. Reserved->SendInProgress = TRUE;
  353. Reserved->Type = SEND_TYPE_SESSION_INIT;
  354. //
  355. // Fill in the IPX header -- the default header has the broadcast
  356. // address on net 0 as the destination IPX address.
  357. //
  358. Header = (NB_CONNECTION UNALIGNED *)
  359. (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
  360. RtlCopyMemory((PVOID)&Header->IpxHeader, &Connection->RemoteHeader, sizeof(IPX_HEADER));
  361. Header->IpxHeader.PacketLength[0] = (UCHAR)((sizeof(NB_CONNECTION)+SessionInitBufferLength) / 256);
  362. Header->IpxHeader.PacketLength[1] = (UCHAR)((sizeof(NB_CONNECTION)+SessionInitBufferLength) % 256);
  363. Header->IpxHeader.PacketType = 0x04;
  364. //
  365. // Now fill in the Netbios header.
  366. //
  367. if (Connection->NewNetbios) {
  368. Header->Session.ConnectionControlFlag = NB_CONTROL_SYSTEM | NB_CONTROL_NEW_NB;
  369. } else {
  370. Header->Session.ConnectionControlFlag = NB_CONTROL_SYSTEM;
  371. }
  372. // Bug#: 158998: We can have a situation where the seqno wont be zero
  373. // if u get a (late) session init frame during active session
  374. // CTEAssert (Connection->CurrentSend.SendSequence == 0);
  375. // CTEAssert (Connection->ReceiveSequence == 1);
  376. if (Connection->ReceiveSequence != 1)
  377. {
  378. DbgPrint("NwlnkNb.NbiSendSessionInitAck: Connection=<%p>: ReceiveSequence=<%d> != 1\n",
  379. Connection, Connection->ReceiveSequence);
  380. }
  381. Header->Session.DataStreamType = NB_CMD_SESSION_DATA;
  382. Header->Session.SourceConnectionId = Connection->LocalConnectionId;
  383. Header->Session.DestConnectionId = Connection->RemoteConnectionId;
  384. Header->Session.SendSequence = 0;
  385. Header->Session.TotalDataLength = (USHORT)SessionInitBufferLength;
  386. Header->Session.Offset = 0;
  387. Header->Session.DataLength = (USHORT)SessionInitBufferLength;
  388. Header->Session.ReceiveSequence = 1;
  389. if (Connection->NewNetbios) {
  390. Header->Session.ReceiveSequenceMax = Connection->LocalRcvSequenceMax;
  391. } else {
  392. Header->Session.BytesReceived = 0;
  393. }
  394. RtlCopyMemory (SessionInitMemory->SourceName, Connection->AddressFile->Address->NetbiosAddress.NetbiosName, 16);
  395. RtlCopyMemory (SessionInitMemory->DestinationName, Connection->RemoteName, 16);
  396. SessionInitMemory->MaximumDataSize = (USHORT)Connection->MaximumPacketSize;
  397. SessionInitMemory->StartTripTime = (USHORT)
  398. ((Device->InitialRetransmissionTime * (Device->KeepAliveCount+1)) / 500);
  399. SessionInitMemory->MaximumPacketTime = SessionInitMemory->StartTripTime + 12;
  400. //
  401. // Should we ref the connection? It doesn't really matter which we do.
  402. //
  403. NbiReferenceDevice (Device, DREF_SESSION_INIT);
  404. NdisChainBufferAtBack (Packet, SessionInitBuffer);
  405. //
  406. // Now send the frame, IPX will adjust the length of the
  407. // first buffer correctly.
  408. //
  409. NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(NB_CONNECTION));
  410. if ((NdisStatus =
  411. (*Device->Bind.SendHandler)(
  412. &Connection->LocalTarget,
  413. Packet,
  414. sizeof(NB_CONNECTION) + SessionInitBufferLength,
  415. sizeof(NB_CONNECTION))) != STATUS_PENDING) {
  416. NbiSendComplete(
  417. Packet,
  418. NdisStatus);
  419. }
  420. } /* NbiSendSessionInitAck */
  421. VOID
  422. NbiSendDataAck(
  423. IN PCONNECTION Connection,
  424. IN NB_ACK_TYPE AckType
  425. IN NB_LOCK_HANDLE_PARAM (LockHandle)
  426. )
  427. /*++
  428. Routine Description:
  429. This routine allocates and sends a data ack frame.
  430. THIS ROUTINE IS CALLED WITH THE LOCK HANDLE HELD AND
  431. RETURNS WITH IT RELEASED.
  432. Arguments:
  433. Connection - The connection on which the frame is sent.
  434. AckType - Indicates if this is a query to the remote,
  435. a response to a received probe, or a request to resend.
  436. LockHandle - The handle with which Connection->Lock was acquired.
  437. Return Value:
  438. None.
  439. --*/
  440. {
  441. PSINGLE_LIST_ENTRY s;
  442. PNB_SEND_RESERVED Reserved;
  443. PNDIS_PACKET Packet;
  444. NB_CONNECTION UNALIGNED * Header;
  445. PDEVICE Device = NbiDevice;
  446. //
  447. // Allocate a packet from the pool.
  448. //
  449. s = NbiPopSendPacket(Device, FALSE);
  450. //
  451. // If we can't allocate a frame, try for the connection
  452. // packet. If that's not available, that's OK since data
  453. // acks are connectionless anyway.
  454. //
  455. if (s == NULL) {
  456. if (!Connection->SendPacketInUse) {
  457. Connection->SendPacketInUse = TRUE;
  458. Packet = PACKET(&Connection->SendPacket);
  459. Reserved = (PNB_SEND_RESERVED)(Packet->ProtocolReserved);
  460. } else {
  461. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  462. return;
  463. }
  464. } else {
  465. Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
  466. Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
  467. }
  468. CTEAssert (Reserved->SendInProgress == FALSE);
  469. Reserved->SendInProgress = TRUE;
  470. Reserved->Type = SEND_TYPE_SESSION_NO_DATA;
  471. Reserved->u.SR_CO.Connection = Connection;
  472. Reserved->u.SR_CO.PacketLength = sizeof(NB_CONNECTION);
  473. //
  474. // Fill in the IPX header -- the default header has the broadcast
  475. // address on net 0 as the destination IPX address.
  476. //
  477. Header = (NB_CONNECTION UNALIGNED *)
  478. (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
  479. RtlCopyMemory((PVOID)&Header->IpxHeader, &Connection->RemoteHeader, sizeof(IPX_HEADER));
  480. Header->IpxHeader.PacketLength[0] = sizeof(NB_CONNECTION) / 256;
  481. Header->IpxHeader.PacketLength[1] = sizeof(NB_CONNECTION) % 256;
  482. Header->IpxHeader.PacketType = 0x04;
  483. //
  484. // Now fill in the Netbios header.
  485. //
  486. switch (AckType) {
  487. case NbiAckQuery: Header->Session.ConnectionControlFlag = NB_CONTROL_SYSTEM | NB_CONTROL_SEND_ACK; break;
  488. case NbiAckResponse: Header->Session.ConnectionControlFlag = NB_CONTROL_SYSTEM; break;
  489. case NbiAckResend: Header->Session.ConnectionControlFlag = NB_CONTROL_SYSTEM | NB_CONTROL_RESEND; break;
  490. }
  491. Header->Session.DataStreamType = NB_CMD_SESSION_DATA;
  492. Header->Session.SourceConnectionId = Connection->LocalConnectionId;
  493. Header->Session.DestConnectionId = Connection->RemoteConnectionId;
  494. Header->Session.SendSequence = Connection->CurrentSend.SendSequence;
  495. Header->Session.TotalDataLength = (USHORT)Connection->CurrentSend.MessageOffset;
  496. Header->Session.Offset = 0;
  497. Header->Session.DataLength = 0;
  498. #if 0
  499. //
  500. // These are set by NbiAssignSequenceAndSend.
  501. //
  502. Header->Session.ReceiveSequence = Connection->ReceiveSequence;
  503. Header->Session.BytesReceived = (USHORT)Connection->CurrentReceive.MessageOffset;
  504. #endif
  505. NbiReferenceConnectionSync(Connection, CREF_FRAME);
  506. //
  507. // Set this so we will accept a probe from a remote without
  508. // the send ack bit on. However if we receive such a request
  509. // we turn this flag off until we get something else from the
  510. // remote.
  511. //
  512. Connection->IgnoreNextDosProbe = FALSE;
  513. Connection->ReceivesWithoutAck = 0;
  514. //
  515. // This frees the lock. IPX will adjust the length of
  516. // the first buffer correctly.
  517. //
  518. NbiAssignSequenceAndSend(
  519. Connection,
  520. Packet
  521. NB_LOCK_HANDLE_ARG(LockHandle));
  522. } /* NbiSendDataAck */
  523. VOID
  524. NbiSendSessionEnd(
  525. IN PCONNECTION Connection
  526. )
  527. /*++
  528. Routine Description:
  529. This routine allocates and sends a session end
  530. frame for the specified connection.
  531. Arguments:
  532. Connection - The connection on which the frame is sent.
  533. Return Value:
  534. None.
  535. --*/
  536. {
  537. PSINGLE_LIST_ENTRY s;
  538. PNB_SEND_RESERVED Reserved;
  539. PNDIS_PACKET Packet;
  540. NB_CONNECTION UNALIGNED * Header;
  541. NDIS_STATUS NdisStatus;
  542. PDEVICE Device = NbiDevice;
  543. //
  544. // Allocate a packet from the pool.
  545. //
  546. s = NbiPopSendPacket(Device, FALSE);
  547. //
  548. // If we can't allocate a frame, that is OK, since
  549. // it is connectionless anyway.
  550. //
  551. if (s == NULL) {
  552. return;
  553. }
  554. Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
  555. Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
  556. CTEAssert (Reserved->SendInProgress == FALSE);
  557. Reserved->SendInProgress = TRUE;
  558. Reserved->Type = SEND_TYPE_SESSION_NO_DATA;
  559. Reserved->u.SR_CO.Connection = Connection;
  560. //
  561. // Fill in the IPX header -- the default header has the broadcast
  562. // address on net 0 as the destination IPX address.
  563. //
  564. Header = (NB_CONNECTION UNALIGNED *)
  565. (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
  566. RtlCopyMemory((PVOID)&Header->IpxHeader, &Connection->RemoteHeader, sizeof(IPX_HEADER));
  567. Header->IpxHeader.PacketLength[0] = sizeof(NB_CONNECTION) / 256;
  568. Header->IpxHeader.PacketLength[1] = sizeof(NB_CONNECTION) % 256;
  569. Header->IpxHeader.PacketType = 0x04;
  570. //
  571. // Now fill in the Netbios header. We don't advance the
  572. // send pointer, since it is the last frame of the session
  573. // and we want it to stay the same in the case of resends.
  574. //
  575. Header->Session.ConnectionControlFlag = NB_CONTROL_SEND_ACK;
  576. Header->Session.DataStreamType = NB_CMD_SESSION_END;
  577. Header->Session.SourceConnectionId = Connection->LocalConnectionId;
  578. Header->Session.DestConnectionId = Connection->RemoteConnectionId;
  579. Header->Session.SendSequence = Connection->CurrentSend.SendSequence;
  580. Header->Session.TotalDataLength = 0;
  581. Header->Session.Offset = 0;
  582. Header->Session.DataLength = 0;
  583. Header->Session.ReceiveSequence = Connection->ReceiveSequence;
  584. if (Connection->NewNetbios) {
  585. Header->Session.ReceiveSequenceMax = Connection->LocalRcvSequenceMax;
  586. } else {
  587. Header->Session.BytesReceived = 0;
  588. }
  589. NbiReferenceConnection (Connection, CREF_FRAME);
  590. //
  591. // Now send the frame, IPX will adjust the length of the
  592. // first buffer correctly.
  593. //
  594. NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(NB_CONNECTION));
  595. if ((NdisStatus =
  596. (*Device->Bind.SendHandler)(
  597. &Connection->LocalTarget,
  598. Packet,
  599. sizeof(NB_CONNECTION),
  600. sizeof(NB_CONNECTION))) != STATUS_PENDING) {
  601. NbiSendComplete(
  602. Packet,
  603. NdisStatus);
  604. }
  605. } /* NbiSendSessionEnd */
  606. VOID
  607. NbiSendSessionEndAck(
  608. IN TDI_ADDRESS_IPX UNALIGNED * RemoteAddress,
  609. IN PIPX_LOCAL_TARGET LocalTarget,
  610. IN NB_SESSION UNALIGNED * SessionEnd
  611. )
  612. /*++
  613. Routine Description:
  614. This routine allocates and sends a session end
  615. frame. Generally it is sent on a connection but we
  616. are not tied to that, to allow us to respond to
  617. session ends from unknown remotes.
  618. Arguments:
  619. RemoteAddress - The remote IPX address.
  620. LocalTarget - The local target of the remote.
  621. SessionEnd - The received session end frame.
  622. Return Value:
  623. None.
  624. --*/
  625. {
  626. PSINGLE_LIST_ENTRY s;
  627. PNB_SEND_RESERVED Reserved;
  628. PNDIS_PACKET Packet;
  629. NB_CONNECTION UNALIGNED * Header;
  630. NDIS_STATUS NdisStatus;
  631. PDEVICE Device = NbiDevice;
  632. //
  633. // Allocate a packet from the pool.
  634. //
  635. s = NbiPopSendPacket(Device, FALSE);
  636. //
  637. // If we can't allocate a frame, that is OK, since
  638. // it is connectionless anyway.
  639. //
  640. if (s == NULL) {
  641. return;
  642. }
  643. Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
  644. Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
  645. CTEAssert (Reserved->SendInProgress == FALSE);
  646. Reserved->SendInProgress = TRUE;
  647. Reserved->Type = SEND_TYPE_SESSION_NO_DATA;
  648. Reserved->u.SR_CO.Connection = NULL;
  649. //
  650. // Fill in the IPX header -- the default header has the broadcast
  651. // address on net 0 as the destination IPX address.
  652. //
  653. Header = (NB_CONNECTION UNALIGNED *)
  654. (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
  655. RtlCopyMemory((PVOID)&Header->IpxHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
  656. RtlCopyMemory(&Header->IpxHeader.DestinationNetwork, (PVOID)RemoteAddress, 12);
  657. Header->IpxHeader.PacketLength[0] = (sizeof(NB_CONNECTION)) / 256;
  658. Header->IpxHeader.PacketLength[1] = (sizeof(NB_CONNECTION)) % 256;
  659. Header->IpxHeader.PacketType = 0x04;
  660. //
  661. // Now fill in the Netbios header.
  662. //
  663. Header->Session.ConnectionControlFlag = 0x00;
  664. Header->Session.DataStreamType = NB_CMD_SESSION_END_ACK;
  665. Header->Session.SourceConnectionId = SessionEnd->DestConnectionId;
  666. Header->Session.DestConnectionId = SessionEnd->SourceConnectionId;
  667. Header->Session.SendSequence = SessionEnd->ReceiveSequence;
  668. Header->Session.TotalDataLength = 0;
  669. Header->Session.Offset = 0;
  670. Header->Session.DataLength = 0;
  671. if (SessionEnd->BytesReceived != 0) { // Will this detect new netbios?
  672. Header->Session.ReceiveSequence = SessionEnd->SendSequence + 1;
  673. Header->Session.ReceiveSequenceMax = SessionEnd->SendSequence + 3;
  674. } else {
  675. Header->Session.ReceiveSequence = SessionEnd->SendSequence;
  676. Header->Session.BytesReceived = 0;
  677. }
  678. NbiReferenceDevice (Device, DREF_FRAME);
  679. //
  680. // Now send the frame, IPX will adjust the length of the
  681. // first buffer correctly.
  682. //
  683. NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(NB_CONNECTION));
  684. if ((NdisStatus =
  685. (*Device->Bind.SendHandler)(
  686. LocalTarget,
  687. Packet,
  688. sizeof(NB_CONNECTION),
  689. sizeof(NB_CONNECTION))) != STATUS_PENDING) {
  690. NbiSendComplete(
  691. Packet,
  692. NdisStatus);
  693. }
  694. } /* NbiSendSessionEndAck */