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.

2564 lines
73 KiB

  1. /*++
  2. Copyright (c) 1989-1993 Microsoft Corporation
  3. Module Name:
  4. rip.c
  5. Abstract:
  6. This module contains code that implements the client-side
  7. RIP support and simple router table support.
  8. Environment:
  9. Kernel mode
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. UCHAR BroadcastAddress[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
  15. NTSTATUS
  16. RipGetLocalTarget(
  17. IN ULONG Segment,
  18. IN TDI_ADDRESS_IPX UNALIGNED * RemoteAddress,
  19. IN UCHAR Type,
  20. OUT PIPX_LOCAL_TARGET LocalTarget,
  21. OUT USHORT Counts[2] OPTIONAL
  22. )
  23. /*++
  24. Routine Description:
  25. This routine looks up the proper route for the specified remote
  26. address. If a RIP request needs to be generated it does so.
  27. NOTE: THIS REQUEST IS CALLED WITH THE SEGMENT LOCK HELD.
  28. NOTE: IN THE CASE OF PnP, THIS COMES WITH THE BIND LOCK SHARED.
  29. Arguments:
  30. Segment - The segment associate with the remote address.
  31. RemoteAddress - The IPX address of the remote.
  32. Type - One of IPX_FIND_ROUTE_NO_RIP, IPX_FIND_ROUTE_RIP_IF_NEEDED,
  33. or IPX_FIND_ROUTE_FORCE_RIP.
  34. LocalTarget - Returns the next router information.
  35. Counts - If specified, used to return the tick and hop count.
  36. Return Value:
  37. STATUS_SUCCESS if a route is found, STATUS_PENDING if a
  38. RIP request needs to be generated, failure status if a
  39. RIP request packet cannot be allocated.
  40. --*/
  41. {
  42. PDEVICE Device = IpxDevice;
  43. PIPX_ROUTE_ENTRY RouteEntry;
  44. PBINDING Binding;
  45. UINT i;
  46. //
  47. // Packets sent to network 0 go on the first adapter also.
  48. //
  49. if (Device->RealAdapters && (RemoteAddress->NetworkAddress == 0)) {
  50. FILL_LOCAL_TARGET(LocalTarget, FIRST_REAL_BINDING);
  51. RtlCopyMemory (LocalTarget->MacAddress, RemoteAddress->NodeAddress, 6);
  52. if (ARGUMENT_PRESENT(Counts)) {
  53. Counts[0] = (USHORT)((839 + NIC_ID_TO_BINDING(Device, FIRST_REAL_BINDING)->MediumSpeed) /
  54. NIC_ID_TO_BINDING(Device, FIRST_REAL_BINDING)->MediumSpeed); // tick count
  55. Counts[1] = 1; // hop count
  56. }
  57. return STATUS_SUCCESS;
  58. }
  59. //
  60. // See if this is a packet sent to our virtual network.
  61. //
  62. if (Device->VirtualNetwork &&
  63. (RemoteAddress->NetworkAddress == Device->SourceAddress.NetworkAddress)) {
  64. //
  65. // Send it through adapter 1.
  66. // Do real loopback.
  67. //
  68. FILL_LOCAL_TARGET(LocalTarget, LOOPBACK_NIC_ID);
  69. RtlCopyMemory (LocalTarget->MacAddress, NIC_ID_TO_BINDING(Device, LOOPBACK_NIC_ID)->LocalMacAddress.Address, 6);
  70. IPX_DEBUG (LOOPB, ("Loopback Nic returned for net: %lx\n", RemoteAddress->NetworkAddress));
  71. if (ARGUMENT_PRESENT(Counts)) {
  72. Counts[0] = 1; // tick count
  73. Counts[1] = 1; // hop count
  74. }
  75. return STATUS_SUCCESS;
  76. }
  77. //
  78. // Look up the route in the table. If the net is one
  79. // of the ones we are directly attached to, this will
  80. // return an entry with the correct flag set.
  81. //
  82. RouteEntry = RipGetRoute(Segment, (PUCHAR)&(RemoteAddress->NetworkAddress));
  83. if (RouteEntry != NULL) {
  84. RouteEntry->Timer = 0;
  85. FILL_LOCAL_TARGET(LocalTarget, RouteEntry->NicId);
  86. if (RouteEntry->Flags & IPX_ROUTER_LOCAL_NET) {
  87. //
  88. // The machine is on the same net, so send it directly.
  89. //
  90. RtlCopyMemory (LocalTarget->MacAddress, RemoteAddress->NodeAddress, 6);
  91. if (RouteEntry->Flags & IPX_ROUTER_GLOBAL_WAN_NET) {
  92. //
  93. // The NicId here is bogus, we have to scan through
  94. // our bindings until we find one whose indicated
  95. // IPX remote node matches the destination node of
  96. // this frame. We don't scan into the duplicate
  97. // binding set members since they won't be WANs.
  98. //
  99. {
  100. ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
  101. for (i = FIRST_REAL_BINDING; i <= Index; i++) {
  102. Binding = NIC_ID_TO_BINDING(Device, i);
  103. if ((Binding != (PBINDING)NULL) &&
  104. (Binding->Adapter->MacInfo.MediumAsync) &&
  105. (RtlEqualMemory(
  106. Binding->WanRemoteNode,
  107. RemoteAddress->NodeAddress,
  108. 6))) {
  109. FILL_LOCAL_TARGET(LocalTarget, MIN( Device->MaxBindings, Binding->NicId));
  110. break;
  111. }
  112. }
  113. }
  114. if (i > (UINT)MIN (Device->MaxBindings, Device->HighestExternalNicId)) {
  115. //
  116. // Bug #17273 return proper error message
  117. //
  118. // return STATUS_DEVICE_DOES_NOT_EXIST;
  119. return STATUS_NETWORK_UNREACHABLE;
  120. }
  121. } else {
  122. //
  123. // Find out if this is a loopback packet. If so, return NicId 0
  124. //
  125. {
  126. ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
  127. for (i = FIRST_REAL_BINDING; i <= Index; i++) {
  128. Binding = NIC_ID_TO_BINDING(Device, i);
  129. //
  130. // Self-directed - loopback
  131. //
  132. if ((Binding != (PBINDING)NULL) &&
  133. (RtlEqualMemory(
  134. Binding->LocalAddress.NodeAddress,
  135. RemoteAddress->NodeAddress,
  136. 6))) {
  137. FILL_LOCAL_TARGET(LocalTarget, LOOPBACK_NIC_ID);
  138. IPX_DEBUG (LOOPB, ("2.Loopback Nic returned for net: %lx\n", RemoteAddress->NetworkAddress));
  139. break;
  140. }
  141. }
  142. }
  143. }
  144. } else {
  145. CTEAssert ((RouteEntry->Flags & IPX_ROUTER_PERMANENT_ENTRY) == 0);
  146. //
  147. // This is not a locally attached net, so if the caller
  148. // is forcing a re-RIP then do that.
  149. //
  150. if (Type == IPX_FIND_ROUTE_FORCE_RIP) {
  151. goto QueueUpRequest;
  152. }
  153. //
  154. // Fill in the address of the next router in the route.
  155. //
  156. RtlCopyMemory (LocalTarget->MacAddress, RouteEntry->NextRouter, 6);
  157. }
  158. if (ARGUMENT_PRESENT(Counts)) {
  159. Counts[0] = RouteEntry->TickCount;
  160. Counts[1] = RouteEntry->HopCount;
  161. }
  162. return STATUS_SUCCESS;
  163. }
  164. QueueUpRequest:
  165. if (Type == IPX_FIND_ROUTE_NO_RIP) {
  166. //
  167. // Bug #17273 return proper error message
  168. //
  169. // return STATUS_DEVICE_DOES_NOT_EXIST;
  170. return STATUS_NETWORK_UNREACHABLE;
  171. } else {
  172. return RipQueueRequest (RemoteAddress->NetworkAddress, RIP_REQUEST);
  173. }
  174. } /* RipGetLocalTarget */
  175. NTSTATUS
  176. RipQueueRequest(
  177. IN ULONG Network,
  178. IN USHORT Operation
  179. )
  180. /*++
  181. Routine Description:
  182. This routine queues up a request for a RIP route. It can be
  183. used to find a specific route or to discover the locally
  184. attached network (if Network is 0). It can also be used
  185. to do a periodic announcement of the virtual net, which
  186. we do once a minute if the router is not bound.
  187. NOTE: THIS REQUEST IS CALLED WITH THE SEGMENT LOCK HELD
  188. IF IT IS A REQUEST AND THE NETWORK IS NOT 0xffffffff.
  189. Arguments:
  190. Network - The network to discover.
  191. Operation - One of RIP_REQUEST, RIP_RESPONSE, or RIP_DOWN.
  192. Return Value:
  193. STATUS_PENDING if the request is queued, failure status
  194. if it could not be.
  195. --*/
  196. {
  197. PDEVICE Device = IpxDevice;
  198. PIPX_SEND_RESERVED Reserved;
  199. PSLIST_ENTRY s;
  200. PLIST_ENTRY p;
  201. PRIP_PACKET RipPacket;
  202. TDI_ADDRESS_IPX RemoteAddress;
  203. TDI_ADDRESS_IPX LocalAddress;
  204. IPX_DEFINE_LOCK_HANDLE (LockHandle)
  205. PNDIS_BUFFER pNdisIpxBuff;
  206. //
  207. // Make sure we only queue a request for net 0xffffffff if we
  208. // are auto-detecting, because we assume that in other places.
  209. //
  210. if ((Network == 0xffffffff) &&
  211. (Device->AutoDetectState != AUTO_DETECT_STATE_RUNNING)) {
  212. return STATUS_BAD_NETWORK_PATH;
  213. }
  214. //
  215. // Try to get a packet to use for the RIP request. We
  216. // allocate this now, but check if it succeeded later,
  217. // to make the locking work better (we need to keep
  218. // the lock between when we check for an existing
  219. // request on this network and when we queue this
  220. // request).
  221. //
  222. s = IpxPopSendPacket (Device);
  223. //
  224. // There was no router table entry for this network, first see
  225. // if there is already a pending request for this route.
  226. //
  227. IPX_GET_LOCK (&Device->Lock, &LockHandle);
  228. if (Operation == RIP_REQUEST) {
  229. for (p = Device->WaitingRipPackets.Flink;
  230. p != &Device->WaitingRipPackets;
  231. p = p->Flink) {
  232. Reserved = CONTAINING_RECORD (p, IPX_SEND_RESERVED, WaitLinkage);
  233. //
  234. // Skip responses.
  235. //
  236. if (Reserved->u.SR_RIP.RetryCount >= 0xfe) {
  237. continue;
  238. }
  239. if (Reserved->u.SR_RIP.Network == Network &&
  240. !Reserved->u.SR_RIP.RouteFound) {
  241. //
  242. // There is already one pending, put back the packet if
  243. // we got one (we hold the lock already).
  244. //
  245. if (s != NULL) {
  246. IPX_PUSH_ENTRY_LIST (&Device->SendPacketList, s, &Device->SListsLock);
  247. }
  248. IPX_FREE_LOCK (&Device->Lock, LockHandle);
  249. return STATUS_PENDING;
  250. }
  251. }
  252. }
  253. if (s == NULL) {
  254. IPX_FREE_LOCK (&Device->Lock, LockHandle);
  255. return STATUS_INSUFFICIENT_RESOURCES;
  256. }
  257. Reserved = CONTAINING_RECORD (s, IPX_SEND_RESERVED, PoolLinkage);
  258. //
  259. // We have the packet, fill it in for this request.
  260. //
  261. Reserved->Identifier = IDENTIFIER_RIP_INTERNAL;
  262. Reserved->SendInProgress = FALSE;
  263. Reserved->DestinationType = DESTINATION_BCAST;
  264. Reserved->u.SR_RIP.CurrentNicId = 0;
  265. Reserved->u.SR_RIP.NoIdAdvance = FALSE;
  266. switch (Operation) {
  267. case RIP_REQUEST: Reserved->u.SR_RIP.RetryCount = 0; break;
  268. case RIP_RESPONSE: Reserved->u.SR_RIP.RetryCount = 0xfe; break;
  269. case RIP_DOWN: Reserved->u.SR_RIP.RetryCount = 0xff; break;
  270. }
  271. Reserved->u.SR_RIP.RouteFound = FALSE;
  272. Reserved->u.SR_RIP.Network = Network;
  273. Reserved->u.SR_RIP.SendTime = Device->RipSendTime;
  274. //
  275. // We aren't guaranteed that this is the case for packets
  276. // on the free list.
  277. //
  278. pNdisIpxBuff = NDIS_BUFFER_LINKAGE (Reserved->HeaderBuffer);
  279. NDIS_BUFFER_LINKAGE (pNdisIpxBuff) = NULL;
  280. //
  281. // Fill in the IPX header at the standard offset (for sending
  282. // to actual bindings it will be moved around if needed). We
  283. // have to construct the local and remote addresses so they
  284. // are in the format that IpxConstructHeader expects.
  285. //
  286. RemoteAddress.NetworkAddress = Network;
  287. RtlCopyMemory (RemoteAddress.NodeAddress, BroadcastAddress, 6);
  288. RemoteAddress.Socket = RIP_SOCKET;
  289. RtlCopyMemory (&LocalAddress, &Device->SourceAddress, FIELD_OFFSET(TDI_ADDRESS_IPX,Socket));
  290. LocalAddress.Socket = RIP_SOCKET;
  291. IpxConstructHeader(
  292. // &Reserved->Header[Device->IncludedHeaderOffset],
  293. &Reserved->Header[MAC_HEADER_SIZE],
  294. sizeof(IPX_HEADER) + sizeof (RIP_PACKET),
  295. RIP_PACKET_TYPE,
  296. &RemoteAddress,
  297. &LocalAddress);
  298. //
  299. // Fill in the RIP request also.
  300. //
  301. #if 0
  302. RipPacket = (PRIP_PACKET)(&Reserved->Header[Device->IncludedHeaderOffset + sizeof(IPX_HEADER)]);
  303. #endif
  304. RipPacket = (PRIP_PACKET)(&Reserved->Header[MAC_HEADER_SIZE + sizeof(IPX_HEADER)]);
  305. RipPacket->Operation = Operation & 0x7fff;
  306. RipPacket->NetworkEntry.NetworkNumber = Network;
  307. if (Operation == RIP_REQUEST) {
  308. RipPacket->NetworkEntry.HopCount = REORDER_USHORT(0xffff);
  309. RipPacket->NetworkEntry.TickCount = REORDER_USHORT(0xffff);
  310. } else if (Operation == RIP_RESPONSE) {
  311. RipPacket->NetworkEntry.HopCount = REORDER_USHORT(1);
  312. RipPacket->NetworkEntry.TickCount = REORDER_USHORT(2); // will be modified when sent
  313. } else {
  314. RipPacket->NetworkEntry.HopCount = REORDER_USHORT(16);
  315. RipPacket->NetworkEntry.TickCount = REORDER_USHORT(16);
  316. }
  317. NdisAdjustBufferLength(pNdisIpxBuff, sizeof(IPX_HEADER) + sizeof(RIP_PACKET));
  318. //
  319. // Now insert this packet in the queue of pending RIP
  320. // requests and start the timer if needed (this is done
  321. // to ensure the RIP_GRANULARITY milliseconds inter-RIP-packet
  322. // delay).
  323. //
  324. IPX_DEBUG (RIP, ("RIP %s for network %lx\n",
  325. (Operation == RIP_REQUEST) ? "request" : ((Operation == RIP_RESPONSE) ? "announce" : "down"),
  326. REORDER_ULONG(Network)));
  327. InsertHeadList(
  328. &Device->WaitingRipPackets,
  329. &Reserved->WaitLinkage);
  330. ++Device->RipPacketCount;
  331. if (!Device->RipShortTimerActive) {
  332. Device->RipShortTimerActive = TRUE;
  333. IpxReferenceDevice (Device, DREF_RIP_TIMER);
  334. CTEStartTimer(
  335. &Device->RipShortTimer,
  336. 1, // 1 ms, i.e. expire immediately
  337. RipShortTimeout,
  338. (PVOID)Device);
  339. }
  340. IpxReferenceDevice (Device, DREF_RIP_PACKET);
  341. IPX_FREE_LOCK (&Device->Lock, LockHandle);
  342. return STATUS_PENDING;
  343. } /* RipQueueRequest */
  344. VOID
  345. RipSendResponse(
  346. IN PBINDING Binding,
  347. IN TDI_ADDRESS_IPX UNALIGNED * RemoteAddress,
  348. IN PIPX_LOCAL_TARGET LocalTarget
  349. )
  350. /*++
  351. Routine Description:
  352. This routine sends a respond to a RIP request from a client --
  353. this is only used if we have a virtual network and the router
  354. is not bound, and somebody queries on the virtual network.
  355. Arguments:
  356. Binding - The binding on which the request was received.
  357. RemoteAddress - The IPX source address of the request.
  358. LocalTarget - The local target of the received packet.
  359. Return Value:
  360. STATUS_PENDING if the request is queued, failure status
  361. if it could not be.
  362. --*/
  363. {
  364. PSLIST_ENTRY s;
  365. PIPX_SEND_RESERVED Reserved;
  366. TDI_ADDRESS_IPX LocalAddress;
  367. PNDIS_PACKET Packet;
  368. PIPX_HEADER IpxHeader;
  369. PRIP_PACKET RipPacket;
  370. PDEVICE Device = IpxDevice;
  371. PBINDING MasterBinding;
  372. NDIS_STATUS NdisStatus;
  373. USHORT TickCount;
  374. PNDIS_BUFFER pNdisIpxBuff;
  375. //
  376. // Get a packet to use for the RIP response.
  377. //
  378. s = IpxPopSendPacket (Device);
  379. if (s == NULL) {
  380. return;
  381. }
  382. IpxReferenceDevice (Device, DREF_RIP_PACKET);
  383. Reserved = CONTAINING_RECORD (s, IPX_SEND_RESERVED, PoolLinkage);
  384. //
  385. // We have the packet, fill it in for this request.
  386. //
  387. Reserved->Identifier = IDENTIFIER_RIP_RESPONSE;
  388. Reserved->DestinationType = DESTINATION_DEF;
  389. CTEAssert (!Reserved->SendInProgress);
  390. Reserved->SendInProgress = TRUE;
  391. //
  392. // We aren't guaranteed that this is the case for packets
  393. // on the free list.
  394. //
  395. pNdisIpxBuff = NDIS_BUFFER_LINKAGE (Reserved->HeaderBuffer);
  396. NDIS_BUFFER_LINKAGE (pNdisIpxBuff) = NULL;
  397. //
  398. // If this binding is a binding set member, round-robin through
  399. // the various bindings when responding. We will get some natural
  400. // round-robinning because broadcast requests are received on
  401. // binding set members in turn, but they are only rotated once
  402. // a second.
  403. //
  404. if (Binding->BindingSetMember) {
  405. //
  406. // It's a binding set member, we round-robin the
  407. // responses across all the cards to distribute
  408. // the traffic.
  409. //
  410. MasterBinding = Binding->MasterBinding;
  411. Binding = MasterBinding->CurrentSendBinding;
  412. MasterBinding->CurrentSendBinding = Binding->NextBinding;
  413. IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
  414. }
  415. //
  416. // Fill in the IPX header at the correct offset.
  417. //
  418. LocalAddress.NetworkAddress = Binding->LocalAddress.NetworkAddress;
  419. RtlCopyMemory (LocalAddress.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
  420. LocalAddress.Socket = RIP_SOCKET;
  421. #if 0
  422. IpxHeader = (PIPX_HEADER)(&Reserved->Header[Binding->DefHeaderSize]);
  423. #endif
  424. IpxHeader = (PIPX_HEADER)(&Reserved->Header[MAC_HEADER_SIZE]);
  425. IpxConstructHeader(
  426. (PUCHAR)IpxHeader,
  427. sizeof(IPX_HEADER) + sizeof (RIP_PACKET),
  428. RIP_PACKET_TYPE,
  429. RemoteAddress,
  430. &LocalAddress);
  431. //
  432. // In case the request comes from net 0, fill that in too.
  433. //
  434. *(UNALIGNED ULONG *)IpxHeader->DestinationNetwork = Binding->LocalAddress.NetworkAddress;
  435. //
  436. // Fill in the RIP request.
  437. //
  438. RipPacket = (PRIP_PACKET)(IpxHeader+1);
  439. RipPacket->Operation = RIP_RESPONSE;
  440. RipPacket->NetworkEntry.NetworkNumber = Device->VirtualNetworkNumber;
  441. RipPacket->NetworkEntry.HopCount = REORDER_USHORT(1);
  442. TickCount = (USHORT)(((839 + Binding->MediumSpeed) / Binding->MediumSpeed) + 1);
  443. RipPacket->NetworkEntry.TickCount = REORDER_USHORT(TickCount);
  444. IPX_DEBUG (RIP, ("RIP response for virtual network %lx\n",
  445. REORDER_ULONG(Device->VirtualNetworkNumber)));
  446. NdisAdjustBufferLength(pNdisIpxBuff, sizeof(IPX_HEADER) + sizeof(RIP_PACKET));
  447. //
  448. // Now submit the packet to NDIS.
  449. //
  450. Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
  451. if ((NdisStatus = IpxSendFrame(
  452. LocalTarget,
  453. Packet,
  454. sizeof(RIP_PACKET) + sizeof(IPX_HEADER),
  455. sizeof(RIP_PACKET) + sizeof(IPX_HEADER))) != NDIS_STATUS_PENDING) {
  456. IpxSendComplete(
  457. (NDIS_HANDLE)Binding->Adapter,
  458. Packet,
  459. NdisStatus);
  460. }
  461. if (Binding->BindingSetMember) {
  462. IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
  463. }
  464. return;
  465. } /* RipSendResponse */
  466. VOID
  467. RipShortTimeout(
  468. CTEEvent * Event,
  469. PVOID Context
  470. )
  471. /*++
  472. Routine Description:
  473. This routine is called when the RIP short timer expires.
  474. It is called every RIP_GRANULARITY milliseconds unless there
  475. is nothing to do.
  476. Arguments:
  477. Event - The event used to queue the timer.
  478. Context - The context, which is the device pointer.
  479. Return Value:
  480. None.
  481. --*/
  482. {
  483. PDEVICE Device = (PDEVICE)Context;
  484. PLIST_ENTRY p;
  485. PIPX_SEND_RESERVED Reserved;
  486. PNDIS_PACKET Packet;
  487. USHORT OldNicId, NewNicId;
  488. ULONG OldOffset, NewOffset;
  489. PIPX_HEADER IpxHeader;
  490. PBINDING Binding, MasterBinding;
  491. NDIS_STATUS NdisStatus;
  492. IPX_DEFINE_LOCK_HANDLE (LockHandle)
  493. #ifdef _PNP_LATER
  494. static IPX_LOCAL_TARGET BroadcastTarget = { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, {0, 0, 0} };
  495. #else
  496. static IPX_LOCAL_TARGET BroadcastTarget = { 0, { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } };
  497. #endif
  498. static ULONG ZeroNetwork = 0;
  499. IPX_DEFINE_LOCK_HANDLE(LockHandle1)
  500. IPX_GET_LOCK (&Device->Lock, &LockHandle);
  501. ++Device->RipSendTime;
  502. if (Device->RipPacketCount == 0) {
  503. Device->RipShortTimerActive = FALSE;
  504. IPX_FREE_LOCK (&Device->Lock, LockHandle);
  505. IpxDereferenceDevice (Device, DREF_RIP_TIMER);
  506. return;
  507. }
  508. //
  509. // Check what is on the queue; this is set up as a
  510. // loop but in fact it rarely does (under no
  511. // circumstances can we send more than one packet
  512. // each time this function executes).
  513. //
  514. while (TRUE) {
  515. p = Device->WaitingRipPackets.Flink;
  516. if (p == &Device->WaitingRipPackets) {
  517. IPX_FREE_LOCK (&Device->Lock, LockHandle);
  518. break;
  519. }
  520. Reserved = CONTAINING_RECORD (p, IPX_SEND_RESERVED, WaitLinkage);
  521. if ((Reserved->u.SR_RIP.RouteFound) && (!Reserved->SendInProgress)) {
  522. (VOID)RemoveHeadList (&Device->WaitingRipPackets);
  523. Reserved->Identifier = IDENTIFIER_IPX;
  524. IPX_PUSH_ENTRY_LIST (&Device->SendPacketList, &Reserved->PoolLinkage, &Device->SListsLock);
  525. --Device->RipPacketCount;
  526. //
  527. // It is OK to do this with the lock held because
  528. // it won't be the last one (we have the RIP_TIMER ref).
  529. //
  530. IpxDereferenceDevice (Device, DREF_RIP_PACKET);
  531. continue;
  532. }
  533. if ((((SHORT)(Device->RipSendTime - Reserved->u.SR_RIP.SendTime)) < 0) ||
  534. Reserved->SendInProgress) {
  535. IPX_FREE_LOCK (&Device->Lock, LockHandle);
  536. break;
  537. }
  538. (VOID)RemoveHeadList (&Device->WaitingRipPackets);
  539. //
  540. // Find the right binding to send to. If NoIdAdvance
  541. // is set, then the binding doesn't need to be changed
  542. // this time (this means we wrapped last time).
  543. //
  544. OldNicId = Reserved->u.SR_RIP.CurrentNicId;
  545. if (!Reserved->u.SR_RIP.NoIdAdvance) {
  546. BOOLEAN FoundNext = FALSE;
  547. //
  548. // To maintain the lock order, release Device lock here and re-acquire later
  549. //
  550. USHORT StartId;
  551. if (Device->ValidBindings == 0) {
  552. IPX_DEBUG(PNP, ("ValidBindings 0 in RipShortTimeOut\n"));
  553. Device->RipShortTimerActive = FALSE;
  554. IPX_FREE_LOCK (&Device->Lock, LockHandle);
  555. IpxDereferenceDevice (Device, DREF_RIP_TIMER);
  556. return;
  557. }
  558. StartId = (USHORT)((OldNicId % MIN (Device->MaxBindings, Device->ValidBindings)) + 1);
  559. NewNicId = StartId;
  560. IPX_FREE_LOCK (&Device->Lock, LockHandle);
  561. IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
  562. do {
  563. Binding = NIC_ID_TO_BINDING(Device, NewNicId);
  564. if (Reserved->u.SR_RIP.Network != 0xffffffff) {
  565. //
  566. // We are looking for a real net; check that
  567. // the next binding is valid. If it is a WAN
  568. // binding, we don't send queries if the router
  569. // is bound. If it is a LAN binding, we don't
  570. // send queries if we are configured for
  571. // SingleNetworkActive and the WAN is up.
  572. // We also don't send queries on binding set
  573. // members which aren't masters.
  574. //
  575. if ((Binding != NULL)
  576. &&
  577. ((!Binding->Adapter->MacInfo.MediumAsync) ||
  578. (!Device->UpperDriverBound[IDENTIFIER_RIP]))
  579. &&
  580. ((Binding->Adapter->MacInfo.MediumAsync) ||
  581. (!Device->SingleNetworkActive) ||
  582. (!Device->ActiveNetworkWan))
  583. &&
  584. ((!Binding->BindingSetMember) ||
  585. (Binding->CurrentSendBinding))) {
  586. FoundNext = TRUE;
  587. break;
  588. }
  589. } else {
  590. //
  591. // We are sending out the initial request to net
  592. // 0xffffffff, to generate traffic so we can figure
  593. // out our real network number. We don't do this
  594. // to nets that already have a number and we don't
  595. // do it on WAN links. We also don't do it on
  596. // auto-detect nets if we have found the default.
  597. //
  598. if ((Binding != NULL) &&
  599. (Binding->TentativeNetworkAddress == 0) &&
  600. (!Binding->Adapter->MacInfo.MediumAsync) &&
  601. (!Binding->AutoDetect || !Binding->Adapter->DefaultAutoDetected)) {
  602. FoundNext = TRUE;
  603. break;
  604. }
  605. }
  606. //
  607. // Why cycle thru the entire list?
  608. //
  609. NewNicId = (USHORT)((NewNicId % MIN (Device->MaxBindings, Device->ValidBindings)) + 1);
  610. } while (NewNicId != StartId);
  611. if (!FoundNext) {
  612. //
  613. // Nothing more needs to be done with this packet,
  614. // leave it off the queue and since we didn't send
  615. // a packet we can check for more.
  616. //
  617. RipCleanupPacket(Device, Reserved);
  618. IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
  619. IPX_GET_LOCK (&Device->Lock, &LockHandle);
  620. IPX_PUSH_ENTRY_LIST (&Device->SendPacketList, &Reserved->PoolLinkage, &Device->SListsLock);
  621. --Device->RipPacketCount;
  622. IpxDereferenceDevice (Device, DREF_RIP_PACKET);
  623. continue;
  624. }
  625. IPX_DEBUG(RIP, ("RIP: FoundNext: %lx, StartId: %lx, OldNicId: %lx, NewNicId: %lx\n", FoundNext, StartId, OldNicId, NewNicId));
  626. IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
  627. IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
  628. //
  629. // Re-acquire the Device lock
  630. //
  631. IPX_GET_LOCK (&Device->Lock, &LockHandle);
  632. Reserved->u.SR_RIP.CurrentNicId = NewNicId;
  633. //
  634. // Move the data around if needed.
  635. //
  636. #if 0
  637. if (OldNicId != NewNicId) {
  638. if (OldNicId == 0) {
  639. OldOffset = Device->IncludedHeaderOffset;
  640. } else {
  641. OldOffset = Device->Bindings[OldNicId]->BcMcHeaderSize;
  642. }
  643. NewOffset = Binding->BcMcHeaderSize;
  644. if (OldOffset != NewOffset) {
  645. RtlMoveMemory(
  646. &Reserved->Header[NewOffset],
  647. &Reserved->Header[OldOffset],
  648. sizeof(IPX_HEADER) + sizeof(RIP_PACKET));
  649. }
  650. }
  651. #endif
  652. if (NewNicId <= OldNicId) {
  653. //
  654. // We found a new binding but we wrapped, so increment
  655. // the counter. If we have done all the resends, or
  656. // this is a response (indicated by retry count of 0xff;
  657. // they are only sent once) then clean up.
  658. //
  659. if ((Reserved->u.SR_RIP.RetryCount >= 0xfe) ||
  660. ((++Reserved->u.SR_RIP.RetryCount) == Device->RipCount)) {
  661. //
  662. // This packet is stale, clean it up and continue.
  663. //
  664. IPX_FREE_LOCK (&Device->Lock, LockHandle);
  665. IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
  666. RipCleanupPacket(Device, Reserved);
  667. IPX_GET_LOCK (&Device->Lock, &LockHandle);
  668. IPX_PUSH_ENTRY_LIST (&Device->SendPacketList, &Reserved->PoolLinkage, &Device->SListsLock);
  669. --Device->RipPacketCount;
  670. IpxDereferenceDevice (Device, DREF_RIP_PACKET);
  671. } else {
  672. //
  673. // We wrapped, so put ourselves back in the queue
  674. // at the end.
  675. //
  676. Reserved->u.SR_RIP.SendTime = (USHORT)(Device->RipSendTime + Device->RipTimeout - 1);
  677. Reserved->u.SR_RIP.NoIdAdvance = TRUE;
  678. InsertTailList (&Device->WaitingRipPackets, &Reserved->WaitLinkage);
  679. //
  680. // Free the Device lock before deref'ing the Binding so we maintain
  681. // the lock order: BindingAccess > GlobalInterLock > Device
  682. //
  683. IPX_FREE_LOCK (&Device->Lock, LockHandle);
  684. IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
  685. IPX_GET_LOCK (&Device->Lock, &LockHandle);
  686. }
  687. continue;
  688. }
  689. //
  690. // To prevent the re-acquire of the device lock, this is moved up...
  691. //
  692. //
  693. // Send it again as soon as possible (it we just wrapped, then
  694. // we will have put ourselves at the tail and won't get here).
  695. //
  696. InsertHeadList (&Device->WaitingRipPackets, &Reserved->WaitLinkage);
  697. CTEAssert (Reserved->Identifier == IDENTIFIER_RIP_INTERNAL);
  698. CTEAssert (!Reserved->SendInProgress);
  699. Reserved->SendInProgress = TRUE;
  700. IPX_FREE_LOCK (&Device->Lock, LockHandle);
  701. } else {
  702. //
  703. // Next time we need to advance the binding.
  704. //
  705. Reserved->u.SR_RIP.NoIdAdvance = FALSE;
  706. NewNicId = OldNicId;
  707. //
  708. // Send it again as soon as possible (it we just wrapped, then
  709. // we will have put ourselves at the tail and won't get here).
  710. //
  711. InsertHeadList (&Device->WaitingRipPackets, &Reserved->WaitLinkage);
  712. CTEAssert (Reserved->Identifier == IDENTIFIER_RIP_INTERNAL);
  713. CTEAssert (!Reserved->SendInProgress);
  714. Reserved->SendInProgress = TRUE;
  715. IPX_FREE_LOCK (&Device->Lock, LockHandle);
  716. IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
  717. Binding = NIC_ID_TO_BINDING(Device, NewNicId);
  718. IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
  719. IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
  720. }
  721. //
  722. // This packet should be sent on binding NewNicId; first
  723. // move the data to the right location for the current
  724. // binding.
  725. //
  726. CTEAssert (Binding == NIC_ID_TO_BINDING(Device, NewNicId)); // temp, just to make sure
  727. // NewOffset = Binding->BcMcHeaderSize;
  728. //
  729. // Now submit the packet to NDIS.
  730. //
  731. Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
  732. FILL_LOCAL_TARGET(&BroadcastTarget, NewNicId);
  733. //
  734. // Modify the header so the packet comes from this
  735. // specific adapter, not the virtual network.
  736. //
  737. // IpxHeader = (PIPX_HEADER)(&Reserved->Header[NewOffset]);
  738. IpxHeader = (PIPX_HEADER)(&Reserved->Header[MAC_HEADER_SIZE]);
  739. if (Reserved->u.SR_RIP.Network == 0xffffffff) {
  740. *(UNALIGNED ULONG *)IpxHeader->SourceNetwork = 0;
  741. } else {
  742. *(UNALIGNED ULONG *)IpxHeader->SourceNetwork = Binding->LocalAddress.NetworkAddress;
  743. }
  744. if (Reserved->u.SR_RIP.RetryCount < 0xfe) {
  745. //
  746. // This is an outgoing query. We round-robin these through
  747. // binding sets.
  748. //
  749. if (Binding->BindingSetMember) {
  750. //
  751. // Shouldn't have any binding sets during initial
  752. // discovery.
  753. //
  754. // 303606
  755. // If we have three lan cards on the same lan with the same fram types,
  756. // then the first two could be in the binding set, while auto detect rip
  757. // packet is outstanding for the third card. So the assertion is not
  758. // necessarily true.
  759. // CTEAssert (Reserved->u.SR_RIP.Network != 0xffffffff);
  760. //
  761. // If we are in a binding set, then use the current binding
  762. // in the set for this send, and advance the current binding.
  763. // The places we have used Binding before here will be fine
  764. // since the binding set members all have the same media
  765. // and frame type.
  766. //
  767. // 303606 not necessarily a master binding
  768. MasterBinding = Binding->MasterBinding;
  769. Binding = MasterBinding->CurrentSendBinding;
  770. MasterBinding->CurrentSendBinding = Binding->NextBinding;
  771. //
  772. // We dont have a lock here - the masterbinding could be bogus
  773. //
  774. IpxDereferenceBinding1(MasterBinding, BREF_DEVICE_ACCESS);
  775. IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
  776. }
  777. }
  778. RtlCopyMemory (IpxHeader->SourceNode, Binding->LocalAddress.NodeAddress, 6);
  779. //
  780. // Bug# 6485
  781. // Rip request, general or specific, is putting the network of the
  782. // node to which the route has to be found in the ipx header remote
  783. // network field. Some novell routers don't like that. This network
  784. // field should be 0.
  785. //
  786. {
  787. PRIP_PACKET RipPacket = (PRIP_PACKET)(&Reserved->Header[MAC_HEADER_SIZE + sizeof(IPX_HEADER)]);
  788. if (RipPacket->Operation != RIP_REQUEST) {
  789. *(UNALIGNED ULONG *)IpxHeader->DestinationNetwork = Binding->LocalAddress.NetworkAddress;
  790. } else {
  791. *(UNALIGNED ULONG *)IpxHeader->DestinationNetwork = 0;
  792. }
  793. }
  794. //
  795. // If this is a RIP_RESPONSE, set the tick count for this
  796. // binding.
  797. //
  798. if (Reserved->u.SR_RIP.RetryCount == 0xfe) {
  799. PRIP_PACKET RipPacket = (PRIP_PACKET)(IpxHeader+1);
  800. USHORT TickCount = (USHORT)
  801. (((839 + Binding->MediumSpeed) / Binding->MediumSpeed) + 1);
  802. RipPacket->NetworkEntry.TickCount = REORDER_USHORT(TickCount);
  803. }
  804. if ((NdisStatus = IpxSendFrame(
  805. &BroadcastTarget,
  806. Packet,
  807. sizeof(RIP_PACKET) + sizeof(IPX_HEADER),
  808. sizeof(RIP_PACKET) + sizeof(IPX_HEADER))) != NDIS_STATUS_PENDING) {
  809. IpxSendComplete(
  810. (NDIS_HANDLE)Binding->Adapter,
  811. Packet,
  812. NdisStatus);
  813. }
  814. IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
  815. break;
  816. }
  817. CTEStartTimer(
  818. &Device->RipShortTimer,
  819. RIP_GRANULARITY,
  820. RipShortTimeout,
  821. (PVOID)Device);
  822. } /* RipShortTimeout */
  823. VOID
  824. RipLongTimeout(
  825. CTEEvent * Event,
  826. PVOID Context
  827. )
  828. /*++
  829. Routine Description:
  830. This routine is called when the RIP long timer expires.
  831. It is called every minute and handles periodic re-RIPping
  832. to ensure that entries are accurate, as well as aging out
  833. of entries if the rip router is not bound.
  834. Arguments:
  835. Event - The event used to queue the timer.
  836. Context - The context, which is the device pointer.
  837. Return Value:
  838. None.
  839. --*/
  840. {
  841. PDEVICE Device = (PDEVICE)Context;
  842. PROUTER_SEGMENT RouterSegment;
  843. PIPX_ROUTE_ENTRY RouteEntry;
  844. UINT Segment;
  845. UINT i;
  846. PBINDING Binding;
  847. IPX_DEFINE_LOCK_HANDLE(LockHandle)
  848. //
  849. // [FW] TRUE if there are no more entries to age out.
  850. //
  851. BOOLEAN fMoreToAge=FALSE;
  852. //
  853. // Rotate the broadcast receiver on all binding sets.
  854. // We can loop up to HighestExternal only since we
  855. // are only interested in finding binding set masters.
  856. //
  857. IPX_DEFINE_LOCK_HANDLE(LockHandle1)
  858. IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
  859. {
  860. ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
  861. for (i = FIRST_REAL_BINDING; i <= Index; i++) {
  862. Binding = NIC_ID_TO_BINDING(Device, i);
  863. if ((Binding != NULL) &&
  864. (Binding->CurrentSendBinding)) {
  865. //
  866. // It is a master, so find the current broadcast
  867. // receiver, then advance it.
  868. //
  869. while (TRUE) {
  870. if (Binding->ReceiveBroadcast) {
  871. Binding->ReceiveBroadcast = FALSE;
  872. IPX_DEBUG(RIP, (" %x set to FALSE\n", Binding));
  873. if (Binding == Binding->NextBinding) {
  874. DbgBreakPoint();
  875. }
  876. Binding->NextBinding->ReceiveBroadcast = TRUE;
  877. IPX_DEBUG(RIP, (" %x set to TRUE\n", Binding->NextBinding));
  878. break;
  879. } else {
  880. Binding = Binding->NextBinding;
  881. }
  882. }
  883. }
  884. }
  885. }
  886. IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
  887. //
  888. // If RIP is bound, we don't do any of this, and
  889. // we stop the timer from running.
  890. //
  891. if (Device->UpperDriverBound[IDENTIFIER_RIP]) {
  892. //
  893. // [FW] For the case when the Forwarder appears after our table has
  894. // been primed, we need to age out these entries....
  895. //
  896. if (Device->ForwarderBound) {
  897. goto ageout;
  898. }
  899. IpxDereferenceDevice (Device, DREF_LONG_TIMER);
  900. return;
  901. }
  902. //
  903. // If we have a virtual net, do our periodic broadcast.
  904. //
  905. if (Device->RipResponder) {
  906. (VOID)RipQueueRequest (Device->VirtualNetworkNumber, RIP_RESPONSE);
  907. }
  908. //
  909. // We need to scan each hash bucket to see if there
  910. // are any active entries which need to be re-RIPped
  911. // for. We also scan for entries that should be timed
  912. // out.
  913. //
  914. ageout:
  915. for (Segment = 0; Segment < Device->SegmentCount; Segment++) {
  916. RouterSegment = &IpxDevice->Segments[Segment];
  917. //
  918. // Don't take the lock if the bucket is empty.
  919. //
  920. if (RouterSegment->Entries.Flink == &RouterSegment->Entries) {
  921. continue;
  922. }
  923. IPX_GET_LOCK (&Device->SegmentLocks[Segment], &LockHandle);
  924. //
  925. // Scan through each entry looking for ones to age.
  926. //
  927. for (RouteEntry = RipGetFirstRoute (Segment);
  928. RouteEntry != (PIPX_ROUTE_ENTRY)NULL;
  929. RouteEntry = RipGetNextRoute (Segment)) {
  930. if (RouteEntry->Flags & IPX_ROUTER_PERMANENT_ENTRY) {
  931. continue;
  932. }
  933. //
  934. // [FW] There are more entries to age
  935. //
  936. fMoreToAge = TRUE;
  937. ++RouteEntry->Timer;
  938. if (RouteEntry->Timer >= Device->RipUsageTime) {
  939. RipDeleteRoute (Segment, RouteEntry);
  940. IpxFreeMemory(RouteEntry, sizeof(IPX_ROUTE_ENTRY), MEMORY_RIP, "RouteEntry");
  941. continue;
  942. }
  943. //
  944. // See if we should re-RIP for this segment. It has
  945. // to have been around for RipAgeTime, and we also
  946. // make sure that the Timer is not too high to
  947. // prevent us from re-RIPping on unused routes.
  948. //
  949. ++RouteEntry->PRIVATE.Reserved[0];
  950. if ((RouteEntry->PRIVATE.Reserved[0] >= Device->RipAgeTime) &&
  951. (RouteEntry->Timer <= Device->RipAgeTime) &&
  952. !Device->ForwarderBound) {
  953. //
  954. // If we successfully queue a request, then reset
  955. // Reserved[0] so we don't re-RIP for a while.
  956. //
  957. if (RipQueueRequest (*(UNALIGNED ULONG *)RouteEntry->Network, RIP_REQUEST) == STATUS_PENDING) {
  958. RouteEntry->PRIVATE.Reserved[0] = 0;
  959. }
  960. }
  961. }
  962. IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
  963. }
  964. //
  965. // [FW] If RIP installed, restart the timer only if there was at least
  966. // one entry which could be aged.
  967. //
  968. if (Device->ForwarderBound) {
  969. if (fMoreToAge) {
  970. IPX_DEBUG(RIP, ("More entries to age - restarting long timer\n"));
  971. CTEStartTimer(
  972. &Device->RipLongTimer,
  973. 60000, // one minute timeout
  974. RipLongTimeout,
  975. (PVOID)Device);
  976. } else {
  977. //
  978. // Else, dont restart the timer and deref the device
  979. //
  980. IPX_DEBUG(RIP, ("No more entries to age - derefing the device\n"));
  981. IpxDereferenceDevice (Device, DREF_LONG_TIMER);
  982. }
  983. } else {
  984. //
  985. // Now restart the timer for the next timeout.
  986. //
  987. if (Device->State == DEVICE_STATE_OPEN) {
  988. CTEStartTimer(
  989. &Device->RipLongTimer,
  990. 60000, // one minute timeout
  991. RipLongTimeout,
  992. (PVOID)Device);
  993. } else {
  994. //
  995. // Send a DOWN packet if needed, then stop ourselves.
  996. //
  997. if (Device->RipResponder) {
  998. if (RipQueueRequest (Device->VirtualNetworkNumber, RIP_DOWN) != STATUS_PENDING) {
  999. //
  1000. // We need to kick this event because the packet completion
  1001. // won't.
  1002. //
  1003. KeSetEvent(
  1004. &Device->UnloadEvent,
  1005. 0L,
  1006. FALSE);
  1007. }
  1008. }
  1009. IpxDereferenceDevice (Device, DREF_LONG_TIMER);
  1010. }
  1011. }
  1012. } /* RipLongTimeout */
  1013. VOID
  1014. RipCleanupPacket(
  1015. IN PDEVICE Device,
  1016. IN PIPX_SEND_RESERVED RipReserved
  1017. )
  1018. /*++
  1019. Routine Description:
  1020. This routine cleans up when a RIP packet times out.
  1021. Arguments:
  1022. Device - The device.
  1023. RipReserved - The ProtocolReserved section of the RIP packet.
  1024. Return Value:
  1025. None.
  1026. --*/
  1027. {
  1028. ULONG Segment;
  1029. IPX_DEFINE_LOCK_HANDLE_PARAM (LockHandle)
  1030. if (RipReserved->u.SR_RIP.RetryCount < 0xfe) {
  1031. if (RipReserved->u.SR_RIP.Network != 0xffffffff) {
  1032. IPX_DEBUG (RIP, ("Timing out RIP for network %lx\n",
  1033. REORDER_ULONG(RipReserved->u.SR_RIP.Network)));
  1034. Segment = RipGetSegment ((PUCHAR)&RipReserved->u.SR_RIP.Network);
  1035. IPX_GET_LOCK (&Device->SegmentLocks[Segment], &LockHandle);
  1036. //
  1037. // Fail all datagrams, etc. that were waiting for
  1038. // this route. This call releases the lock.
  1039. //
  1040. RipHandleRoutePending(
  1041. Device,
  1042. (PUCHAR)&(RipReserved->u.SR_RIP.Network),
  1043. LockHandle,
  1044. FALSE,
  1045. NULL,
  1046. 0,
  1047. 0);
  1048. } else {
  1049. //
  1050. // This was the initial query looking for networks --
  1051. // signal the init thread which is waiting.
  1052. //
  1053. IPX_DEBUG (AUTO_DETECT, ("Signalling auto-detect event\n"));
  1054. KeSetEvent(
  1055. &Device->AutoDetectEvent,
  1056. 0L,
  1057. FALSE);
  1058. }
  1059. } else if (RipReserved->u.SR_RIP.RetryCount == 0xff) {
  1060. //
  1061. // This is a DOWN message, set the device event that
  1062. // is waiting for it to complete.
  1063. //
  1064. KeSetEvent(
  1065. &Device->UnloadEvent,
  1066. 0L,
  1067. FALSE);
  1068. }
  1069. //
  1070. // Put the RIP packet back in the pool.
  1071. //
  1072. RipReserved->Identifier = IDENTIFIER_IPX;
  1073. } /* RipCleanupPacket */
  1074. VOID
  1075. RipProcessResponse(
  1076. IN PDEVICE Device,
  1077. IN PIPX_LOCAL_TARGET LocalTarget,
  1078. IN RIP_PACKET UNALIGNED * RipPacket
  1079. )
  1080. /*++
  1081. Routine Description:
  1082. This routine processes a RIP response from the specified
  1083. local target, indicating a route to the network in the RIP
  1084. header.
  1085. Arguments:
  1086. Device - The device.
  1087. LocalTarget - The router that the frame was received from.
  1088. RipPacket - The RIP response header.
  1089. Return Value:
  1090. None.
  1091. --*/
  1092. {
  1093. PIPX_SEND_RESERVED RipReserved; // ProtocolReserved of RIP packet
  1094. ULONG Segment;
  1095. PIPX_ROUTE_ENTRY RouteEntry, OldRouteEntry;
  1096. PLIST_ENTRY p;
  1097. IPX_DEFINE_LOCK_HANDLE_PARAM (LockHandle)
  1098. //
  1099. // Since we have received a RIP response for this network.
  1100. // kill the waiting RIP packets for it if it exists.
  1101. //
  1102. IPX_GET_LOCK (&Device->Lock, &LockHandle);
  1103. for (p = Device->WaitingRipPackets.Flink;
  1104. p != &Device->WaitingRipPackets;
  1105. p = p->Flink) {
  1106. RipReserved = CONTAINING_RECORD (p, IPX_SEND_RESERVED, WaitLinkage);
  1107. if (RipReserved->u.SR_RIP.RetryCount >= 0xfe) {
  1108. continue;
  1109. }
  1110. if (RipReserved->u.SR_RIP.Network ==
  1111. RipPacket->NetworkEntry.NetworkNumber) {
  1112. break;
  1113. }
  1114. }
  1115. if (p == &Device->WaitingRipPackets) {
  1116. //
  1117. // No packets pending on this, return.
  1118. //
  1119. IPX_FREE_LOCK (&Device->Lock, LockHandle);
  1120. return;
  1121. }
  1122. //
  1123. // Put the RIP packet back in the pool.
  1124. //
  1125. IPX_DEBUG (RIP, ("Got RIP response for network %lx\n",
  1126. REORDER_ULONG(RipPacket->NetworkEntry.NetworkNumber)));
  1127. RipReserved->u.SR_RIP.RouteFound = TRUE;
  1128. if (!RipReserved->SendInProgress) {
  1129. //
  1130. // If the send is done destroy it now, otherwise
  1131. // when it pops up in RipShortTimeout it will get
  1132. // destroyed because RouteFound is TRUE.
  1133. //
  1134. RemoveEntryList (p);
  1135. RipReserved->Identifier = IDENTIFIER_IPX;
  1136. IPX_PUSH_ENTRY_LIST (&Device->SendPacketList, &RipReserved->PoolLinkage, &Device->SListsLock);
  1137. --Device->RipPacketCount;
  1138. IPX_FREE_LOCK (&Device->Lock, LockHandle);
  1139. IpxDereferenceDevice (Device, DREF_RIP_PACKET);
  1140. } else {
  1141. IPX_FREE_LOCK (&Device->Lock, LockHandle);
  1142. }
  1143. //
  1144. // Try to allocate and add a router segment unless the
  1145. // RIP router is active...if we don't that is fine, we'll
  1146. // just re-RIP later.
  1147. //
  1148. Segment = RipGetSegment ((PUCHAR)&RipPacket->NetworkEntry.NetworkNumber);
  1149. if (!Device->UpperDriverBound[IDENTIFIER_RIP]) {
  1150. RouteEntry = IpxAllocateMemory(sizeof(IPX_ROUTE_ENTRY), MEMORY_RIP, "RouteEntry");
  1151. if (RouteEntry != (PIPX_ROUTE_ENTRY)NULL) {
  1152. *(UNALIGNED LONG *)RouteEntry->Network = RipPacket->NetworkEntry.NetworkNumber;
  1153. RouteEntry->NicId = NIC_FROM_LOCAL_TARGET(LocalTarget);
  1154. RouteEntry->NdisBindingContext = NIC_ID_TO_BINDING(Device, RouteEntry->NicId)->Adapter->NdisBindingHandle;
  1155. // What if this is NULL?? -> make sure not null before calling this routine.
  1156. RouteEntry->Flags = 0;
  1157. RouteEntry->Timer = 0;
  1158. RouteEntry->PRIVATE.Reserved[0] = 0;
  1159. RouteEntry->Segment = Segment;
  1160. RouteEntry->HopCount = REORDER_USHORT(RipPacket->NetworkEntry.HopCount);
  1161. RouteEntry->TickCount = REORDER_USHORT(RipPacket->NetworkEntry.TickCount);
  1162. InitializeListHead (&RouteEntry->AlternateRoute);
  1163. InitializeListHead (&RouteEntry->NicLinkage);
  1164. RtlCopyMemory (RouteEntry->NextRouter, LocalTarget->MacAddress, 6);
  1165. IPX_GET_LOCK (&Device->SegmentLocks[Segment], &LockHandle);
  1166. //
  1167. // Replace any existing routes. This is OK because once
  1168. // we get the first response to a RIP packet on a given
  1169. // route, we will take the packet out of the queue and
  1170. // ignore further responses. We will only get a bad route
  1171. // if we do two requests really quickly and there
  1172. // are two routes, and the second response to the first
  1173. // request is picked up as the first response to the second
  1174. // request.
  1175. //
  1176. if ((OldRouteEntry = RipGetRoute (Segment, (PUCHAR)&(RipPacket->NetworkEntry.NetworkNumber))) != NULL) {
  1177. //
  1178. // These are saved so timeouts etc. happen right.
  1179. //
  1180. RouteEntry->Flags = OldRouteEntry->Flags;
  1181. RouteEntry->Timer = OldRouteEntry->Timer;
  1182. RipDeleteRoute (Segment, OldRouteEntry);
  1183. IpxFreeMemory(OldRouteEntry, sizeof(IPX_ROUTE_ENTRY), MEMORY_RIP, "RouteEntry");
  1184. }
  1185. RipAddRoute (Segment, RouteEntry);
  1186. } else {
  1187. IPX_GET_LOCK (&Device->SegmentLocks[Segment], &LockHandle);
  1188. }
  1189. } else {
  1190. IPX_GET_LOCK (&Device->SegmentLocks[Segment], &LockHandle);
  1191. }
  1192. //
  1193. // Complete all datagrams etc. that were waiting
  1194. // for this route. This call releases the lock.
  1195. //
  1196. RipHandleRoutePending(
  1197. Device,
  1198. (PUCHAR)&(RipPacket->NetworkEntry.NetworkNumber),
  1199. LockHandle,
  1200. TRUE,
  1201. LocalTarget,
  1202. (USHORT)(REORDER_USHORT(RipPacket->NetworkEntry.HopCount)),
  1203. (USHORT)(REORDER_USHORT(RipPacket->NetworkEntry.TickCount))
  1204. );
  1205. } /* RipProcessResponse */
  1206. VOID
  1207. RipHandleRoutePending(
  1208. IN PDEVICE Device,
  1209. IN UCHAR Network[4],
  1210. IN CTELockHandle LockHandle,
  1211. IN BOOLEAN Success,
  1212. IN OPTIONAL PIPX_LOCAL_TARGET LocalTarget,
  1213. IN OPTIONAL USHORT HopCount,
  1214. IN OPTIONAL USHORT TickCount
  1215. )
  1216. /*++
  1217. Routine Description:
  1218. This routine cleans up pending datagrams, find route
  1219. requests, and GET_LOCAL_TARGET ioctls that were
  1220. waiting for a route to be found.
  1221. THIS ROUTINE IS CALLED WITH THE SEGMENT LOCK HELD AND
  1222. RETURNS WITH IT RELEASED.
  1223. Arguments:
  1224. Device - The device.
  1225. Network - The network in question.
  1226. LockHandle - The handle used to acquire the lock.
  1227. Success - TRUE if the route was successfully found.
  1228. LocalTarget - If Success is TRUE, the local target for the route.
  1229. HopCount - If Success is TRUE, the hop count for the route,
  1230. in machine order.
  1231. TickCount - If Success is TRUE, the tick count for the route,
  1232. in machine order.
  1233. Return Value:
  1234. None.
  1235. --*/
  1236. {
  1237. LIST_ENTRY DatagramList;
  1238. LIST_ENTRY FindRouteList;
  1239. LIST_ENTRY GetLocalTargetList;
  1240. LIST_ENTRY ReripNetnumList;
  1241. PIPX_SEND_RESERVED WaitReserved; // ProtocolReserved of waiting packet
  1242. PIPX_FIND_ROUTE_REQUEST FindRouteRequest;
  1243. PREQUEST GetLocalTargetRequest;
  1244. PREQUEST ReripNetnumRequest;
  1245. PISN_ACTION_GET_LOCAL_TARGET GetLocalTarget;
  1246. PIPX_NETNUM_DATA NetnumData;
  1247. ULONG Segment;
  1248. PBINDING Binding, SendBinding;
  1249. PLIST_ENTRY p;
  1250. PNDIS_PACKET Packet;
  1251. PIPX_HEADER IpxHeader;
  1252. ULONG HeaderSize;
  1253. NDIS_STATUS NdisStatus;
  1254. ULONG NetworkUlong = *(UNALIGNED ULONG *)Network;
  1255. InitializeListHead (&DatagramList);
  1256. InitializeListHead (&FindRouteList);
  1257. InitializeListHead (&GetLocalTargetList);
  1258. InitializeListHead (&ReripNetnumList);
  1259. //
  1260. // Put all packets that were waiting for a route to
  1261. // this network on DatagramList. They will be sent
  1262. // or failed later in the routine.
  1263. //
  1264. Segment = RipGetSegment (Network);
  1265. p = Device->Segments[Segment].WaitingForRoute.Flink;
  1266. while (p != &Device->Segments[Segment].WaitingForRoute) {
  1267. WaitReserved = CONTAINING_RECORD (p, IPX_SEND_RESERVED, WaitLinkage);
  1268. p = p->Flink;
  1269. #if 0
  1270. if (*(UNALIGNED ULONG *)(((PIPX_HEADER)(&WaitReserved->Header[Device->IncludedHeaderOffset]))->DestinationNetwork) ==
  1271. NetworkUlong) {
  1272. #endif
  1273. if (*(UNALIGNED ULONG *)(((PIPX_HEADER)(&WaitReserved->Header[MAC_HEADER_SIZE]))->DestinationNetwork) ==
  1274. NetworkUlong) {
  1275. RemoveEntryList (&WaitReserved->WaitLinkage);
  1276. InsertTailList (&DatagramList, &WaitReserved->WaitLinkage);
  1277. }
  1278. }
  1279. //
  1280. // Put all find route requests for this network on
  1281. // FindRouteList. They will be completed later in the
  1282. // routine.
  1283. //
  1284. p = Device->Segments[Segment].FindWaitingForRoute.Flink;
  1285. while (p != &Device->Segments[Segment].FindWaitingForRoute) {
  1286. FindRouteRequest = CONTAINING_RECORD (p, IPX_FIND_ROUTE_REQUEST, Linkage);
  1287. p = p->Flink;
  1288. if (*(UNALIGNED ULONG *)(FindRouteRequest->Network) ==
  1289. NetworkUlong) {
  1290. RemoveEntryList (&FindRouteRequest->Linkage);
  1291. InsertTailList (&FindRouteList, &FindRouteRequest->Linkage);
  1292. }
  1293. }
  1294. //
  1295. // Put all get local target action requests for this
  1296. // network on GetLocalTargetList. They will be completed
  1297. // later in the routine.
  1298. //
  1299. p = Device->Segments[Segment].WaitingLocalTarget.Flink;
  1300. while (p != &Device->Segments[Segment].WaitingLocalTarget) {
  1301. GetLocalTargetRequest = LIST_ENTRY_TO_REQUEST(p);
  1302. p = p->Flink;
  1303. GetLocalTarget = (PISN_ACTION_GET_LOCAL_TARGET)REQUEST_INFORMATION(GetLocalTargetRequest);
  1304. if (GetLocalTarget->IpxAddress.NetworkAddress == NetworkUlong) {
  1305. RemoveEntryList (REQUEST_LINKAGE(GetLocalTargetRequest));
  1306. InsertTailList (&GetLocalTargetList, REQUEST_LINKAGE(GetLocalTargetRequest));
  1307. }
  1308. }
  1309. //
  1310. // Put all MIPX_RERIPNETNUM action requests for this
  1311. // network on ReripNetnumList. They will be completed
  1312. // later in the routine.
  1313. //
  1314. p = Device->Segments[Segment].WaitingReripNetnum.Flink;
  1315. while (p != &Device->Segments[Segment].WaitingReripNetnum) {
  1316. ReripNetnumRequest = LIST_ENTRY_TO_REQUEST(p);
  1317. p = p->Flink;
  1318. NetnumData = (PIPX_NETNUM_DATA)REQUEST_INFORMATION(ReripNetnumRequest);
  1319. if (*(UNALIGNED ULONG *)NetnumData->netnum == NetworkUlong) {
  1320. RemoveEntryList (REQUEST_LINKAGE(ReripNetnumRequest));
  1321. InsertTailList (&ReripNetnumList, REQUEST_LINKAGE(ReripNetnumRequest));
  1322. }
  1323. }
  1324. IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
  1325. //
  1326. // For sends we will use the master binding of a binding
  1327. // set, but we'll return the real NicId for people who
  1328. // want that.
  1329. //
  1330. if (Success) {
  1331. Binding = NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(LocalTarget));
  1332. if (Binding->BindingSetMember) {
  1333. SendBinding = Binding->MasterBinding;
  1334. FILL_LOCAL_TARGET(LocalTarget, MIN( Device->MaxBindings, SendBinding->NicId));
  1335. } else {
  1336. SendBinding = Binding;
  1337. }
  1338. }
  1339. //
  1340. // Now that the lock is free, process all packets on
  1341. // DatagramList.
  1342. //
  1343. // NOTE: May misorder packets if they come in right now...
  1344. //
  1345. for (p = DatagramList.Flink; p != &DatagramList ; ) {
  1346. WaitReserved = CONTAINING_RECORD (p, IPX_SEND_RESERVED, WaitLinkage);
  1347. p = p->Flink;
  1348. Packet = CONTAINING_RECORD (WaitReserved, NDIS_PACKET, ProtocolReserved[0]);
  1349. #if DBG
  1350. CTEAssert (!WaitReserved->SendInProgress);
  1351. WaitReserved->SendInProgress = TRUE;
  1352. #endif
  1353. if (Success) {
  1354. IPX_DEBUG (RIP, ("Found queued packet %lx\n", WaitReserved));
  1355. if (REQUEST_INFORMATION(WaitReserved->u.SR_DG.Request) >
  1356. SendBinding->RealMaxDatagramSize) {
  1357. IPX_DEBUG (SEND, ("Queued send %d bytes too large (%d)\n",
  1358. REQUEST_INFORMATION(WaitReserved->u.SR_DG.Request),
  1359. SendBinding->RealMaxDatagramSize));
  1360. IpxSendComplete(
  1361. (NDIS_HANDLE)NULL,
  1362. Packet,
  1363. STATUS_INVALID_BUFFER_SIZE);
  1364. } else {
  1365. #if 0
  1366. if (WaitReserved->DestinationType == DESTINATION_DEF) {
  1367. HeaderSize = SendBinding->DefHeaderSize;
  1368. } else {
  1369. HeaderSize = SendBinding->BcMcHeaderSize;
  1370. }
  1371. IpxHeader = (PIPX_HEADER)
  1372. (&WaitReserved->Header[HeaderSize]);
  1373. #endif
  1374. IpxHeader = (PIPX_HEADER)
  1375. (&WaitReserved->Header[MAC_HEADER_SIZE]);
  1376. //
  1377. // Move the header to the correct location now that
  1378. // we know the NIC ID to send to.
  1379. //
  1380. #if 0
  1381. if (HeaderSize != Device->IncludedHeaderOffset) {
  1382. RtlMoveMemory(
  1383. IpxHeader,
  1384. &WaitReserved->Header[Device->IncludedHeaderOffset],
  1385. sizeof(IPX_HEADER));
  1386. }
  1387. #endif
  1388. if (Device->MultiCardZeroVirtual ||
  1389. (IpxHeader->DestinationSocket == SAP_SOCKET)) {
  1390. //
  1391. // These frames need to look like they come from the
  1392. // local network, not the virtual one.
  1393. //
  1394. *(UNALIGNED ULONG *)IpxHeader->SourceNetwork = SendBinding->LocalAddress.NetworkAddress;
  1395. RtlCopyMemory (IpxHeader->SourceNode, SendBinding->LocalAddress.NodeAddress, 6);
  1396. }
  1397. //
  1398. // Fill in the MAC header and submit the frame to NDIS.
  1399. //
  1400. #ifdef SUNDOWN
  1401. if ((NdisStatus = IpxSendFrame(
  1402. LocalTarget,
  1403. Packet,
  1404. (ULONG) REQUEST_INFORMATION(WaitReserved->u.SR_DG.Request) + sizeof(IPX_HEADER),
  1405. sizeof(IPX_HEADER))) != NDIS_STATUS_PENDING) {
  1406. #else
  1407. if ((NdisStatus = IpxSendFrame(
  1408. LocalTarget,
  1409. Packet,
  1410. REQUEST_INFORMATION(WaitReserved->u.SR_DG.Request) + sizeof(IPX_HEADER),
  1411. sizeof(IPX_HEADER))) != NDIS_STATUS_PENDING) {
  1412. #endif
  1413. IpxSendComplete(
  1414. (NDIS_HANDLE)SendBinding->Adapter,
  1415. Packet,
  1416. NdisStatus);
  1417. }
  1418. }
  1419. } else {
  1420. IPX_DEBUG (RIP, ("Timing out packet %lx\n", WaitReserved));
  1421. IpxSendComplete(
  1422. (NDIS_HANDLE)NULL,
  1423. Packet,
  1424. STATUS_BAD_NETWORK_PATH);
  1425. }
  1426. }
  1427. //
  1428. // Since we round-robin outgoing rip packets, we just use the
  1429. // real NicId here for find route and get local target requests.
  1430. // We changed LocalTarget->NicId to be the master above.
  1431. //
  1432. if (Success) {
  1433. FILL_LOCAL_TARGET(LocalTarget, MIN( Device->MaxBindings, Binding->NicId));
  1434. }
  1435. for (p = FindRouteList.Flink; p != &FindRouteList ; ) {
  1436. FindRouteRequest = CONTAINING_RECORD (p, IPX_FIND_ROUTE_REQUEST, Linkage);
  1437. p = p->Flink;
  1438. if (Success) {
  1439. PUSHORT Counts;
  1440. IPX_DEBUG (RIP, ("Found queued find route %lx\n", FindRouteRequest));
  1441. FindRouteRequest->LocalTarget = *LocalTarget;
  1442. Counts = (PUSHORT)&FindRouteRequest->Reserved2;
  1443. Counts[0] = TickCount;
  1444. Counts[1] = HopCount;
  1445. } else {
  1446. IPX_DEBUG (RIP, ("Timing out find route %lx\n", FindRouteRequest));
  1447. }
  1448. (*Device->UpperDrivers[FindRouteRequest->Identifier].FindRouteCompleteHandler)(
  1449. FindRouteRequest,
  1450. Success);
  1451. }
  1452. for (p = GetLocalTargetList.Flink; p != &GetLocalTargetList ; ) {
  1453. GetLocalTargetRequest = LIST_ENTRY_TO_REQUEST(p);
  1454. p = p->Flink;
  1455. GetLocalTarget = (PISN_ACTION_GET_LOCAL_TARGET)REQUEST_INFORMATION(GetLocalTargetRequest);
  1456. if (Success) {
  1457. IPX_DEBUG (RIP, ("Found queued LOCAL_TARGET action %lx\n", GetLocalTargetRequest));
  1458. GetLocalTarget->LocalTarget = *LocalTarget;
  1459. REQUEST_INFORMATION(GetLocalTargetRequest) = sizeof(ISN_ACTION_GET_LOCAL_TARGET);
  1460. REQUEST_STATUS(GetLocalTargetRequest) = STATUS_SUCCESS;
  1461. } else {
  1462. IPX_DEBUG (RIP, ("Timing out LOCAL_TARGET action %lx\n", GetLocalTargetRequest));
  1463. REQUEST_INFORMATION(GetLocalTargetRequest) = 0;
  1464. REQUEST_STATUS(GetLocalTargetRequest) = STATUS_BAD_NETWORK_PATH;
  1465. }
  1466. IpxCompleteRequest(GetLocalTargetRequest);
  1467. IpxFreeRequest(Device, GetLocalTargetRequest);
  1468. }
  1469. //
  1470. // NOTE: LocalTarget->NicId now points to the real binding
  1471. // not the master, so we use SendBinding->NicId below.
  1472. //
  1473. for (p = ReripNetnumList.Flink; p != &ReripNetnumList ; ) {
  1474. ReripNetnumRequest = LIST_ENTRY_TO_REQUEST(p);
  1475. p = p->Flink;
  1476. NetnumData = (PIPX_NETNUM_DATA)REQUEST_INFORMATION(ReripNetnumRequest);
  1477. if (Success) {
  1478. IPX_DEBUG (RIP, ("Found queued MIPX_RERIPNETNUM action %lx\n", ReripNetnumRequest));
  1479. NetnumData->hopcount = HopCount;
  1480. NetnumData->netdelay = TickCount;
  1481. NetnumData->cardnum = (INT)(MIN( Device->MaxBindings, SendBinding->NicId) - 1);
  1482. RtlMoveMemory (NetnumData->router, LocalTarget->MacAddress, 6);
  1483. REQUEST_INFORMATION(ReripNetnumRequest) =
  1484. FIELD_OFFSET(NWLINK_ACTION, Data[0]) + sizeof(IPX_NETNUM_DATA);
  1485. REQUEST_STATUS(ReripNetnumRequest) = STATUS_SUCCESS;
  1486. } else {
  1487. IPX_DEBUG (RIP, ("Timing out MIPX_RERIPNETNUM action %lx\n", ReripNetnumRequest));
  1488. REQUEST_INFORMATION(ReripNetnumRequest) = 0;
  1489. REQUEST_STATUS(ReripNetnumRequest) = STATUS_BAD_NETWORK_PATH;
  1490. }
  1491. IpxCompleteRequest(ReripNetnumRequest);
  1492. IpxFreeRequest(Device, ReripNetnumRequest);
  1493. }
  1494. } /* RipHandleRoutePending */
  1495. NTSTATUS
  1496. RipInsertLocalNetwork(
  1497. IN ULONG Network,
  1498. IN USHORT NicId,
  1499. IN NDIS_HANDLE NdisBindingContext,
  1500. IN USHORT Count
  1501. )
  1502. /*++
  1503. Routine Description:
  1504. This routine creates a router entry for a local network
  1505. and inserts it in the table.
  1506. Arguments:
  1507. Network - The network.
  1508. NicId - The NIC ID used to route packets
  1509. NdisBindingHandle - The binding handle used for NdisSend
  1510. Count - The tick and hop count for this network (will be
  1511. 0 for the virtual net and 1 for attached nets)
  1512. Return Value:
  1513. The status of the operation.
  1514. --*/
  1515. {
  1516. PIPX_ROUTE_ENTRY RouteEntry;
  1517. PDEVICE Device = IpxDevice;
  1518. ULONG Segment;
  1519. IPX_DEFINE_LOCK_HANDLE (LockHandle)
  1520. //
  1521. // We should allocate the memory in the binding/device
  1522. // structure itself.
  1523. //
  1524. RouteEntry = IpxAllocateMemory(sizeof(IPX_ROUTE_ENTRY), MEMORY_RIP, "RouteEntry");
  1525. if (RouteEntry == (PIPX_ROUTE_ENTRY)NULL) {
  1526. return STATUS_INSUFFICIENT_RESOURCES;
  1527. }
  1528. Segment = RipGetSegment ((PUCHAR)&Network);
  1529. *(UNALIGNED LONG *)RouteEntry->Network = Network;
  1530. RouteEntry->NicId = NicId;
  1531. RouteEntry->NdisBindingContext = NdisBindingContext;
  1532. if (NicId == 0) {
  1533. RouteEntry->Flags = IPX_ROUTER_PERMANENT_ENTRY;
  1534. } else {
  1535. RouteEntry->Flags = IPX_ROUTER_PERMANENT_ENTRY | IPX_ROUTER_LOCAL_NET;
  1536. }
  1537. RouteEntry->Segment = Segment;
  1538. RouteEntry->TickCount = Count;
  1539. RouteEntry->HopCount = 1;
  1540. InitializeListHead (&RouteEntry->AlternateRoute);
  1541. InitializeListHead (&RouteEntry->NicLinkage);
  1542. //
  1543. // RouteEntry->NextRouter is not used for the virtual net or
  1544. // when LOCAL_NET is set (i.e. every net that we will add here).
  1545. //
  1546. RtlZeroMemory (RouteEntry->NextRouter, 6);
  1547. IPX_GET_LOCK (&Device->SegmentLocks[Segment], &LockHandle);
  1548. //
  1549. // Make sure one doesn't exist.
  1550. //
  1551. if (RipGetRoute(Segment, (PUCHAR)&Network) != NULL) {
  1552. IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
  1553. IpxFreeMemory (RouteEntry, sizeof(IPX_ROUTE_ENTRY), MEMORY_RIP, "RouteEntry");
  1554. return STATUS_DUPLICATE_NAME;
  1555. }
  1556. //
  1557. // Add this new entry.
  1558. //
  1559. if (RipAddRoute (Segment, RouteEntry)) {
  1560. IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
  1561. return STATUS_SUCCESS;
  1562. } else {
  1563. IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
  1564. IpxFreeMemory (RouteEntry, sizeof(IPX_ROUTE_ENTRY), MEMORY_RIP, "RouteEntry");
  1565. return STATUS_INSUFFICIENT_RESOURCES;
  1566. }
  1567. } /* RipInsertLocalNetwork */
  1568. VOID
  1569. RipAdjustForBindingChange(
  1570. IN USHORT NicId,
  1571. IN USHORT NewNicId,
  1572. IN IPX_BINDING_CHANGE_TYPE ChangeType
  1573. )
  1574. /*++
  1575. Routine Description:
  1576. This routine is called when an auto-detect binding is
  1577. deleted or moved, or a WAN line goes down.
  1578. It scans the RIP database for routes equal to this NIC ID
  1579. and modifies them appropriately. If ChangeType is
  1580. IpxBindingDeleted it will subract one from any NIC IDs
  1581. in the database that are higher than NicId. It is assumed
  1582. that other code is readjusting the Device->Bindings
  1583. array.
  1584. Arguments:
  1585. NicId - The NIC ID of the deleted binding.
  1586. NewNicId - The new NIC ID, for IpxBindingMoved changes.
  1587. ChangeType - Either IpxBindingDeleted, IpxBindingMoved,
  1588. or IpxBindingDown.
  1589. Return Value:
  1590. None.
  1591. --*/
  1592. {
  1593. PDEVICE Device = IpxDevice;
  1594. PIPX_ROUTE_ENTRY RouteEntry;
  1595. UINT Segment;
  1596. CTELockHandle LockHandle;
  1597. for (Segment = 0; Segment < Device->SegmentCount; Segment++) {
  1598. CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
  1599. //
  1600. // Scan through each entry comparing the NIC ID.
  1601. //
  1602. for (RouteEntry = RipGetFirstRoute (Segment);
  1603. RouteEntry != (PIPX_ROUTE_ENTRY)NULL;
  1604. RouteEntry = RipGetNextRoute (Segment)) {
  1605. if (RouteEntry->NicId == NicId) {
  1606. if (ChangeType != IpxBindingMoved) {
  1607. IPX_DEBUG (AUTO_DETECT, ("Deleting route entry %lx, binding deleted\n", RouteEntry));
  1608. RipDeleteRoute (Segment, RouteEntry);
  1609. } else {
  1610. IPX_DEBUG (AUTO_DETECT, ("Changing NIC ID for route entry %lx\n", RouteEntry));
  1611. RouteEntry->NicId = NewNicId;
  1612. }
  1613. //
  1614. // If the NicId is 0, we dont adjust the other entries' NicId's - this is to support the removal
  1615. // of the Virtual Net # which resides at NicId=0.
  1616. //
  1617. } else if (NicId && (ChangeType != IpxBindingDown) && (RouteEntry->NicId > NicId)) {
  1618. IPX_DEBUG (AUTO_DETECT, ("Decrementing NIC ID for route entry %lx\n", RouteEntry));
  1619. --RouteEntry->NicId;
  1620. }
  1621. }
  1622. CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
  1623. }
  1624. } /* RipAdjustForBindingChange */
  1625. UINT
  1626. RipGetSegment(
  1627. IN UCHAR Network[4]
  1628. )
  1629. /*++
  1630. Routine Description:
  1631. This routine returns the correct segment for the specified
  1632. network.
  1633. Arguments:
  1634. Network - The network.
  1635. Return Value:
  1636. The segment.
  1637. --*/
  1638. {
  1639. ULONG Total;
  1640. Total = Network[0] ^ Network[1] ^ Network[2] ^ Network[3];
  1641. return (Total % IpxDevice->SegmentCount);
  1642. } /* RipGetSegment */
  1643. PIPX_ROUTE_ENTRY
  1644. RipGetRoute(
  1645. IN UINT Segment,
  1646. IN UCHAR Network[4]
  1647. )
  1648. /*++
  1649. Routine Description:
  1650. This routine returns the router table entry for the given
  1651. network, which is in the specified segment of the table.
  1652. THE SEGMENT LOCK MUST BE HELD. The returned data is valid
  1653. until the segment lock is released or other operations
  1654. (add/delete) are performed on the segment.
  1655. Arguments:
  1656. Segment - The segment corresponding to the network.
  1657. Network - The network.
  1658. Return Value:
  1659. The router table entry, or NULL if none exists for this network.
  1660. --*/
  1661. {
  1662. PLIST_ENTRY p;
  1663. PROUTER_SEGMENT RouterSegment;
  1664. PIPX_ROUTE_ENTRY RouteEntry;
  1665. RouterSegment = &IpxDevice->Segments[Segment];
  1666. for (p = RouterSegment->Entries.Flink;
  1667. p != &RouterSegment->Entries;
  1668. p = p->Flink) {
  1669. RouteEntry = CONTAINING_RECORD(
  1670. p,
  1671. IPX_ROUTE_ENTRY,
  1672. PRIVATE.Linkage);
  1673. if ((*(UNALIGNED LONG *)RouteEntry->Network) ==
  1674. (*(UNALIGNED LONG *)Network)) {
  1675. return RouteEntry;
  1676. }
  1677. }
  1678. return NULL;
  1679. } /* RipGetRoute */
  1680. BOOLEAN
  1681. RipAddRoute(
  1682. IN UINT Segment,
  1683. IN PIPX_ROUTE_ENTRY RouteEntry
  1684. )
  1685. /*++
  1686. Routine Description:
  1687. This routine stores a router table entry in the
  1688. table, which must belong in the specified segment.
  1689. THE SEGMENT LOCK MUST BE HELD. Storage for the entry
  1690. is allocated and filled in by the caller.
  1691. Arguments:
  1692. Segment - The segment corresponding to the network.
  1693. RouteEntry - The router table entry.
  1694. Return Value:
  1695. TRUE if the entry was successfully inserted.
  1696. --*/
  1697. {
  1698. IPX_DEBUG (RIP, ("Adding route for network %lx (%d)\n",
  1699. REORDER_ULONG(*(UNALIGNED ULONG *)RouteEntry->Network), Segment));
  1700. InsertTailList(
  1701. &IpxDevice->Segments[Segment].Entries,
  1702. &RouteEntry->PRIVATE.Linkage);
  1703. return TRUE;
  1704. } /* RipAddRoute */
  1705. BOOLEAN
  1706. RipDeleteRoute(
  1707. IN UINT Segment,
  1708. IN PIPX_ROUTE_ENTRY RouteEntry
  1709. )
  1710. /*++
  1711. Routine Description:
  1712. This routine deletes a router table entry in the
  1713. table, which must belong in the specified segment.
  1714. THE SEGMENT LOCK MUST BE HELD. Storage for the entry
  1715. is freed by the caller.
  1716. Arguments:
  1717. Segment - The segment corresponding to the network.
  1718. RouteEntry - The router table entry.
  1719. Return Value:
  1720. TRUE if the entry was successfully deleted.
  1721. --*/
  1722. {
  1723. PROUTER_SEGMENT RouterSegment = &IpxDevice->Segments[Segment];
  1724. IPX_DEBUG (RIP, ("Deleting route for network %lx (%d)\n",
  1725. REORDER_ULONG(*(UNALIGNED ULONG *)RouteEntry->Network), Segment));
  1726. //
  1727. // If the current enumeration point for this segment is here,
  1728. // adjust the pointer before deleting the entry. We make it
  1729. // point to the previous entry so GetNextRoute will work.
  1730. //
  1731. if (RouterSegment->EnumerateLocation == &RouteEntry->PRIVATE.Linkage) {
  1732. RouterSegment->EnumerateLocation = RouterSegment->EnumerateLocation->Blink;
  1733. }
  1734. RemoveEntryList (&RouteEntry->PRIVATE.Linkage);
  1735. return TRUE;
  1736. } /* RipDeleteRoute */
  1737. PIPX_ROUTE_ENTRY
  1738. RipGetFirstRoute(
  1739. IN UINT Segment
  1740. )
  1741. /*++
  1742. Routine Description:
  1743. This routine returns the first router table entry in the
  1744. segment. THE SEGMENT LOCK MUST BE HELD. It is used in
  1745. conjunction with RipGetNextRoute to enumerate all the
  1746. entries in a segment.
  1747. Arguments:
  1748. Segment - The segment being enumerated.
  1749. Return Value:
  1750. The first router table entry, or NULL if the segment is empty.
  1751. --*/
  1752. {
  1753. PIPX_ROUTE_ENTRY FirstEntry;
  1754. PROUTER_SEGMENT RouterSegment = &IpxDevice->Segments[Segment];
  1755. RouterSegment->EnumerateLocation = RouterSegment->Entries.Flink;
  1756. if (RouterSegment->EnumerateLocation == &RouterSegment->Entries) {
  1757. return NULL;
  1758. } else {
  1759. FirstEntry = CONTAINING_RECORD(
  1760. RouterSegment->EnumerateLocation,
  1761. IPX_ROUTE_ENTRY,
  1762. PRIVATE.Linkage);
  1763. return FirstEntry;
  1764. }
  1765. } /* RipGetFirstRoute */
  1766. PIPX_ROUTE_ENTRY
  1767. RipGetNextRoute(
  1768. IN UINT Segment
  1769. )
  1770. /*++
  1771. Routine Description:
  1772. This routine returns the next router table entry in the
  1773. segment. THE SEGMENT LOCK MUST BE HELD. It is used in
  1774. conjunction with RipGetFirstRoute to enumerate all the
  1775. entries in a segment.
  1776. It is illegal to call RipGetNextRoute on a segment
  1777. without first calling RipGetFirstRoute. The segment
  1778. lock must be held for the duration of the enumeration
  1779. of a single segment. It is legal to stop enumerating
  1780. the segment in the middle.
  1781. Arguments:
  1782. Segment - The segment being enumerated.
  1783. Return Value:
  1784. The next router table entry, or NULL if the end of the
  1785. segment is reached.
  1786. --*/
  1787. {
  1788. PIPX_ROUTE_ENTRY NextEntry;
  1789. PROUTER_SEGMENT RouterSegment = &IpxDevice->Segments[Segment];
  1790. RouterSegment->EnumerateLocation = RouterSegment->EnumerateLocation->Flink;
  1791. if (RouterSegment->EnumerateLocation == &RouterSegment->Entries) {
  1792. return NULL;
  1793. } else {
  1794. NextEntry = CONTAINING_RECORD(
  1795. RouterSegment->EnumerateLocation,
  1796. IPX_ROUTE_ENTRY,
  1797. PRIVATE.Linkage);
  1798. return NextEntry;
  1799. }
  1800. } /* RipGetNextRoute */
  1801. VOID
  1802. RipDropRemoteEntries(
  1803. VOID
  1804. )
  1805. /*++
  1806. Routine Description:
  1807. This routine deletes all non-local entries from the
  1808. RIP database. It is called when the WAN line goes up
  1809. or down and we want to remove all existing entries.
  1810. Arguments:
  1811. None.
  1812. Return Value:
  1813. None.
  1814. --*/
  1815. {
  1816. PDEVICE Device = IpxDevice;
  1817. PIPX_ROUTE_ENTRY RouteEntry;
  1818. UINT Segment;
  1819. CTELockHandle LockHandle;
  1820. for (Segment = 0; Segment < Device->SegmentCount; Segment++) {
  1821. CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
  1822. //
  1823. // Scan through, deleting everything but local entries.
  1824. //
  1825. for (RouteEntry = RipGetFirstRoute (Segment);
  1826. RouteEntry != (PIPX_ROUTE_ENTRY)NULL;
  1827. RouteEntry = RipGetNextRoute (Segment)) {
  1828. if ((RouteEntry->Flags & IPX_ROUTER_PERMANENT_ENTRY) == 0) {
  1829. IPX_DEBUG (AUTO_DETECT, ("Deleting route entry %lx, dropping remote entries\n", RouteEntry));
  1830. RipDeleteRoute (Segment, RouteEntry);
  1831. }
  1832. }
  1833. CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
  1834. }
  1835. } /* RipDropRemoteEntries */