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.

1701 lines
49 KiB

  1. #include "precomp.h"
  2. // Memory zone for interfaces
  3. ZONE_HEADER InterfaceZone;
  4. // Segment size in interface sone
  5. ULONG InterfaceSegmentSize=
  6. sizeof(INTERFACE_CB)*NUM_INTERFACES_PER_SEGMENT
  7. +sizeof (ZONE_SEGMENT_HEADER);
  8. KSPIN_LOCK InterfaceZoneLock;
  9. // Interface tables
  10. LIST_ENTRY *InterfaceIndexHash; // Hash by interface index
  11. PINTERFACE_CB *ClientNodeHash; // Hash by node on qlobal net
  12. INTERFACE_CB TheInternalInterface; // The internal interface
  13. PINTERFACE_CB InternalInterface=&TheInternalInterface;
  14. KSPIN_LOCK InterfaceTableLock; // Protection for interface hash tables
  15. // Memory Zone for routes
  16. ZONE_HEADER RouteZone;
  17. // Segment size in route sone
  18. ULONG RouteSegmentSize=DEF_ROUTE_SEGMENT_SIZE;
  19. KSPIN_LOCK RouteZoneLock;
  20. // Route tables
  21. PFWD_ROUTE *RouteHash;
  22. PFWD_ROUTE GlobalRoute;
  23. ULONG GlobalNetwork;
  24. // NB Route table
  25. PNB_ROUTE *NBRouteHash;
  26. // Reader-writer lock to wait for all readers to drain when
  27. // updating the route tables
  28. RW_LOCK RWLock;
  29. // Mutex to serialize writers to route tables
  30. FAST_MUTEX WriterMutex;
  31. // Sizes of the tables
  32. ULONG RouteHashSize; // Must be specified
  33. ULONG InterfaceHashSize=DEF_INTERFACE_HASH_SIZE;
  34. ULONG ClientHashSize=DEF_CLIENT_HASH_SIZE;
  35. ULONG NBRouteHashSize=DEF_NB_ROUTE_HASH_SIZE;
  36. //*** max send pkts queued limit: over this limit the send pkts get discarded
  37. ULONG MaxSendPktsQueued = MAX_SEND_PKTS_QUEUED;
  38. INT WanPacketListId = -1;
  39. // Initial memory block allocated for the tables
  40. CHAR *TableBlock = NULL;
  41. ULONG InterfaceAllocCount = 0;
  42. ULONG InterfaceFreeCount = 0;
  43. // Hash functions
  44. #define InterfaceIndexHashFunc(Interface) (Interface%InterfaceHashSize)
  45. #define ClientNodeHashFunc(Node64) ((UINT)(Node64%ClientHashSize))
  46. #define NetworkNumberHashFunc(Network) (Network%RouteHashSize)
  47. #define NetbiosNameHashFunc(Name128) ((UINT)(Name128[0]+Name128[1])%NBRouteHashSize)
  48. /*++
  49. *******************************************************************
  50. A l l o c a t e R o u t e
  51. Routine Description:
  52. Allocates memory for route from memory zone reserved
  53. for route storage. Extends zone if there are no
  54. free blocks in currently allocated segements.
  55. Arguments:
  56. None
  57. Return Value:
  58. Pointer to allocated route
  59. *******************************************************************
  60. --*/
  61. PFWD_ROUTE
  62. AllocateRoute (
  63. void
  64. ) {
  65. PFWD_ROUTE fwRoute;
  66. KIRQL oldIRQL;
  67. KeAcquireSpinLock (&RouteZoneLock, &oldIRQL);
  68. // Check if there are free blocks in the zone
  69. if (ExIsFullZone (&RouteZone)) {
  70. // Try to allocate new segment if not
  71. NTSTATUS status;
  72. PVOID segment = ExAllocatePoolWithTag
  73. (NonPagedPool, RouteSegmentSize, FWD_POOL_TAG);
  74. if (segment==NULL) {
  75. KeReleaseSpinLock (&RouteZoneLock, oldIRQL);
  76. IpxFwdDbgPrint (DBG_ROUTE_TABLE, DBG_ERROR,
  77. ("IpxFwd: Can't allocate route zone segment.\n"));
  78. return NULL;
  79. }
  80. status = ExExtendZone (&RouteZone, segment, RouteSegmentSize);
  81. ASSERTMSG ("Could not extend RouteZone ", NT_SUCCESS (status));
  82. }
  83. fwRoute = (PFWD_ROUTE)ExAllocateFromZone (&RouteZone);
  84. KeReleaseSpinLock (&RouteZoneLock, oldIRQL);
  85. return fwRoute;
  86. }
  87. /*++
  88. *******************************************************************
  89. F r e e R o u t e
  90. Routine Description:
  91. Releases memory allocated for route to route memory
  92. zone.
  93. Arguments:
  94. fwRoute - route block to release
  95. Return Value:
  96. None
  97. *******************************************************************
  98. --*/
  99. VOID
  100. FreeRoute (
  101. PFWD_ROUTE fwRoute
  102. ) {
  103. IpxFwdDbgPrint (DBG_ROUTE_TABLE, DBG_INFORMATION,
  104. ("IpxFwd: Freeing route block %08lx.\n", fwRoute));
  105. ASSERT (fwRoute->FR_InterfaceReference==NULL);
  106. ExInterlockedFreeToZone(&RouteZone,fwRoute,&RouteZoneLock);
  107. }
  108. /*++
  109. *******************************************************************
  110. A l l o c a t e I n t e r f a c e
  111. Routine Description:
  112. Allocates memory for interface from memory zone reserved
  113. for interface storage. Extends zone if there are no
  114. free blocks in currently allocated segements.
  115. Arguments:
  116. None
  117. Return Value:
  118. Pointer to allocated route
  119. *******************************************************************
  120. --*/
  121. PINTERFACE_CB
  122. AllocateInterface (
  123. void
  124. ) {
  125. PINTERFACE_CB ifCB;
  126. KIRQL oldIRQL;
  127. KeAcquireSpinLock (&RouteZoneLock, &oldIRQL);
  128. // Check if there are free blocks in the zone
  129. if (ExIsFullZone (&InterfaceZone)) {
  130. // Try to allocate new segment if not
  131. NTSTATUS status;
  132. PVOID segment = ExAllocatePoolWithTag
  133. (NonPagedPool, InterfaceSegmentSize, FWD_POOL_TAG);
  134. if (segment==NULL) {
  135. KeReleaseSpinLock (&RouteZoneLock, oldIRQL);
  136. IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_ERROR,
  137. ("IpxFwd: Can't allocate interface zone segment.\n"));
  138. return NULL;
  139. }
  140. status = ExExtendZone (&InterfaceZone, segment, InterfaceSegmentSize);
  141. ASSERTMSG ("Could not extend InterfaceZone ", NT_SUCCESS (status));
  142. }
  143. ifCB = (PINTERFACE_CB)ExAllocateFromZone (&InterfaceZone);
  144. KeReleaseSpinLock (&RouteZoneLock, oldIRQL);
  145. InterlockedIncrement(&InterfaceAllocCount);
  146. return ifCB;
  147. }
  148. /*++
  149. *******************************************************************
  150. F r e e I n t e r f a c e
  151. Routine Description:
  152. Releases memory allocated for interface to interface memory
  153. zone.
  154. Arguments:
  155. fwRoute - route block to release
  156. Return Value:
  157. None
  158. *******************************************************************
  159. --*/
  160. VOID
  161. FreeInterface (
  162. PINTERFACE_CB ifCB
  163. ) {
  164. KIRQL oldIRQL;
  165. IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_WARNING,
  166. ("IpxFwd: Freeing icb %08lx.\n", ifCB));
  167. ASSERT(ifCB->ICB_Stats.OperationalState==FWD_OPER_STATE_DOWN);
  168. KeAcquireSpinLock (&InterfaceZoneLock, &oldIRQL);
  169. ExFreeToZone(&InterfaceZone, ifCB);
  170. KeReleaseSpinLock (&InterfaceZoneLock, oldIRQL);
  171. InterlockedIncrement(&InterfaceFreeCount);
  172. }
  173. /*++
  174. *******************************************************************
  175. C r e a t e T a b l e s
  176. Routine Description:
  177. Allocates and intializes all hash tables and related structures
  178. Arguments:
  179. None
  180. Return Value:
  181. STATUS_SUCCESS - tables were created ok
  182. STATUS_INSUFFICIENT_RESOURCES - resource allocation failed
  183. *******************************************************************
  184. --*/
  185. NTSTATUS
  186. CreateTables (
  187. void
  188. ) {
  189. UINT i;
  190. CHAR *segment;
  191. NTSTATUS status;
  192. ULONG blockSize;
  193. ASSERT (TableBlock==NULL);
  194. blockSize = (ULONG) ROUND_TO_PAGES (
  195. InterfaceHashSize*sizeof(*InterfaceIndexHash)
  196. +ClientHashSize*sizeof(*ClientNodeHash)
  197. +RouteHashSize*sizeof(*RouteHash)
  198. +NBRouteHashSize*sizeof(*NBRouteHash)
  199. +InterfaceSegmentSize
  200. +RouteSegmentSize
  201. );
  202. // Allocate first segment for route zone
  203. TableBlock = segment = (CHAR *)ExAllocatePoolWithTag (
  204. NonPagedPool, blockSize, FWD_POOL_TAG);
  205. if (segment!=NULL) {
  206. InterfaceIndexHash = (LIST_ENTRY *)segment;
  207. segment = (CHAR *)ALIGN_UP((ULONG_PTR)(InterfaceIndexHash+InterfaceHashSize),ULONGLONG);
  208. ClientNodeHash = (PINTERFACE_CB *)segment;
  209. segment = (CHAR *)ALIGN_UP((ULONG_PTR)(ClientNodeHash+ClientHashSize),ULONGLONG);
  210. RouteHash = (PFWD_ROUTE *)segment;
  211. segment = (CHAR *)ALIGN_UP((ULONG_PTR)(RouteHash + RouteHashSize),ULONGLONG);
  212. NBRouteHash = (PNB_ROUTE *)segment;
  213. segment = (CHAR *)ALIGN_UP((ULONG_PTR)(NBRouteHash + NBRouteHashSize),ULONGLONG);
  214. status = ExInitializeZone (&InterfaceZone,
  215. ALIGN_UP(sizeof (INTERFACE_CB),ULONGLONG),
  216. segment,
  217. InterfaceSegmentSize);
  218. ASSERTMSG ("Could not initalize InterfaceZone ",
  219. NT_SUCCESS (status));
  220. segment = (CHAR *)ALIGN_UP((ULONG_PTR)(segment+InterfaceSegmentSize),ULONGLONG);
  221. status = ExInitializeZone (&RouteZone,
  222. ALIGN_UP(sizeof (FWD_ROUTE), ULONGLONG),
  223. segment,
  224. blockSize - (ULONG)(segment - TableBlock));
  225. ASSERTMSG ("Could not initalize RouteZone ", NT_SUCCESS (status));
  226. // No global route yet
  227. GlobalRoute = NULL;
  228. GlobalNetwork = 0xFFFFFFFF;
  229. InternalInterface = &TheInternalInterface;
  230. InitICB (InternalInterface,
  231. FWD_INTERNAL_INTERFACE_INDEX,
  232. FWD_IF_PERMANENT,
  233. TRUE,
  234. FWD_NB_DELIVER_ALL);
  235. #if DBG
  236. InitializeListHead (&InternalInterface->ICB_InSendQueue);
  237. #endif
  238. KeInitializeSpinLock (&InterfaceTableLock);
  239. KeInitializeSpinLock (&InterfaceZoneLock);
  240. KeInitializeSpinLock (&RouteZoneLock);
  241. InitializeRWLock (&RWLock);
  242. ExInitializeFastMutex (&WriterMutex);
  243. // Initialize hash tables buckets
  244. for (i=0; i<InterfaceHashSize; i++)
  245. InitializeListHead (&InterfaceIndexHash[i]);
  246. for (i=0; i<ClientHashSize; i++) {
  247. ClientNodeHash[i] = NULL;
  248. }
  249. for (i=0; i<RouteHashSize; i++) {
  250. RouteHash[i] = NULL;
  251. }
  252. for (i=0; i<NBRouteHashSize; i++) {
  253. NBRouteHash[i] = NULL;
  254. }
  255. return STATUS_SUCCESS;
  256. }
  257. else {
  258. IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_ERROR,
  259. ("IpxFwd: Could not allocate table block!\n"));
  260. }
  261. return STATUS_INSUFFICIENT_RESOURCES;
  262. }
  263. /*++
  264. *******************************************************************
  265. D e l e t e T a b l e s
  266. Routine Description:
  267. Releases resources allocated for all hash tables
  268. Arguments:
  269. None
  270. Return Value:
  271. STATUS_SUCCESS - tables were freed ok
  272. *******************************************************************
  273. --*/
  274. NTSTATUS
  275. DeleteTables (
  276. void
  277. ) {
  278. UINT i;
  279. PVOID segment;
  280. if (TableBlock==NULL) {
  281. IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_ERROR, ("Tables already deleted.\n"));
  282. return STATUS_SUCCESS;
  283. }
  284. // First get rid of all routes
  285. // (that should release all references to interface
  286. // control blocks
  287. for (i=0; i<RouteHashSize; i++) {
  288. while (RouteHash[i]!=NULL) {
  289. PFWD_ROUTE fwRoute = RouteHash[i];
  290. RouteHash[i] = fwRoute->FR_Next;
  291. if (fwRoute->FR_InterfaceReference!=GLOBAL_INTERFACE_REFERENCE) {
  292. ReleaseInterfaceReference (fwRoute->FR_InterfaceReference);
  293. }
  294. fwRoute->FR_InterfaceReference = NULL;
  295. ReleaseRouteReference (fwRoute);
  296. }
  297. }
  298. // Don't forget about global route
  299. if (GlobalRoute!=NULL) {
  300. GlobalRoute->FR_InterfaceReference = NULL;
  301. ReleaseRouteReference (GlobalRoute);
  302. GlobalRoute = NULL;
  303. GlobalNetwork = 0xFFFFFFFF;
  304. }
  305. // Now we should be able to release all interfaces
  306. for (i=0; i<InterfaceHashSize; i++) {
  307. while (!IsListEmpty (&InterfaceIndexHash[i])) {
  308. PINTERFACE_CB ifCB = CONTAINING_RECORD (InterfaceIndexHash[i].Flink,
  309. INTERFACE_CB,
  310. ICB_IndexHashLink);
  311. RemoveEntryList (&ifCB->ICB_IndexHashLink);
  312. if (ifCB->ICB_Stats.OperationalState==FWD_OPER_STATE_UP) {
  313. switch (ifCB->ICB_InterfaceType) {
  314. case FWD_IF_PERMANENT:
  315. DeregisterPacketConsumer (ifCB->ICB_PacketListId);
  316. break;
  317. case FWD_IF_DEMAND_DIAL:
  318. case FWD_IF_LOCAL_WORKSTATION:
  319. case FWD_IF_REMOTE_WORKSTATION:
  320. break;
  321. default:
  322. ASSERTMSG ("Invalid interface type ", FALSE);
  323. break;
  324. }
  325. if (ifCB->ICB_CashedInterface!=NULL)
  326. ReleaseInterfaceReference (ifCB->ICB_CashedInterface);
  327. ifCB->ICB_CashedInterface = NULL;
  328. if (ifCB->ICB_CashedRoute!=NULL)
  329. ReleaseRouteReference (ifCB->ICB_CashedRoute);
  330. ifCB->ICB_CashedRoute = NULL;
  331. if (ifCB->ICB_Network==GlobalNetwork)
  332. DeleteGlobalNetClient (ifCB);
  333. IPXCloseAdapterProc (ifCB->ICB_AdapterContext);
  334. ReleaseInterfaceReference (ifCB); // Binding reference
  335. }
  336. if (IS_IF_CONNECTING (ifCB)) {
  337. SET_IF_NOT_CONNECTING (ifCB);
  338. DequeueConnectionRequest (ifCB);
  339. }
  340. while (!IsListEmpty (&ifCB->ICB_ExternalQueue)) {
  341. PPACKET_TAG pktTag;
  342. pktTag = CONTAINING_RECORD (ifCB->ICB_ExternalQueue.Flink,
  343. PACKET_TAG, PT_QueueLink);
  344. RemoveEntryList (&pktTag->PT_QueueLink);
  345. ReleaseInterfaceReference (pktTag->PT_InterfaceReference);
  346. FreePacket (pktTag);
  347. }
  348. while (!IsListEmpty (&ifCB->ICB_InternalQueue)) {
  349. PINTERNAL_PACKET_TAG pktTag;
  350. pktTag = CONTAINING_RECORD (ifCB->ICB_InternalQueue.Flink,
  351. INTERNAL_PACKET_TAG, IPT_QueueLink);
  352. RemoveEntryList (&pktTag->IPT_QueueLink);
  353. IPXInternalSendCompletProc (&pktTag->IPT_Target,
  354. pktTag->IPT_Packet,
  355. pktTag->IPT_Length,
  356. STATUS_NETWORK_UNREACHABLE);
  357. ReleaseInterfaceReference (pktTag->IPT_InterfaceReference);
  358. ExFreePool (pktTag);
  359. }
  360. ifCB->ICB_Stats.OperationalState = FWD_OPER_STATE_DOWN;
  361. if (ifCB->ICB_NBRoutes!=NULL) {
  362. DeleteNBRoutes (ifCB->ICB_NBRoutes, ifCB->ICB_NBRouteCount);
  363. ifCB->ICB_NBRoutes = NULL;
  364. }
  365. ReleaseInterfaceReference (ifCB);
  366. }
  367. }
  368. if (InternalInterface->ICB_NBRoutes!=NULL) {
  369. DeleteNBRoutes (InternalInterface->ICB_NBRoutes,
  370. InternalInterface->ICB_NBRouteCount);
  371. InternalInterface->ICB_NBRoutes = NULL;
  372. }
  373. if (InternalInterface->ICB_Stats.OperationalState==FWD_OPER_STATE_UP) {
  374. InternalInterface->ICB_Stats.OperationalState = FWD_OPER_STATE_DOWN;
  375. ReleaseInterfaceReference (InternalInterface); // Binding reference
  376. }
  377. ReleaseInterfaceReference (InternalInterface);
  378. // Release extra memory segments used for route table entries
  379. segment = PopEntryList (&RouteZone.SegmentList);
  380. while (RouteZone.SegmentList.Next!=NULL) {
  381. ExFreePool (segment);
  382. segment = PopEntryList (&RouteZone.SegmentList);
  383. }
  384. // Release extra memory segments used for interface table entries
  385. segment = PopEntryList (&InterfaceZone.SegmentList);
  386. while (InterfaceZone.SegmentList.Next!=NULL) {
  387. ExFreePool (segment);
  388. segment = PopEntryList (&InterfaceZone.SegmentList);
  389. }
  390. ExFreePool (TableBlock);
  391. TableBlock = NULL;
  392. return STATUS_SUCCESS;
  393. }
  394. /*++
  395. *******************************************************************
  396. L o c a t e I n t e r f a c e
  397. Routine Description:
  398. Finds interface control block in interface
  399. index hash table. Optionally returns the
  400. insertion point pointer if interface block
  401. with given index is not in the table.
  402. Arguments:
  403. InterfaceIndex - unique id of the interface
  404. insertBefore - buffer to place the pointer to
  405. hash table element where interface
  406. block should be inserted if it is not
  407. already in the table
  408. Return Value:
  409. Pointer to interface control block if found
  410. NULL otherwise
  411. *******************************************************************
  412. --*/
  413. PINTERFACE_CB
  414. LocateInterface (
  415. ULONG InterfaceIndex,
  416. PLIST_ENTRY *insertBefore OPTIONAL
  417. ) {
  418. PLIST_ENTRY cur;
  419. PINTERFACE_CB ifCB;
  420. PLIST_ENTRY HashList;
  421. ASSERT (InterfaceIndex!=FWD_INTERNAL_INTERFACE_INDEX);
  422. // Find hash bucket
  423. HashList = &InterfaceIndexHash[InterfaceIndexHashFunc(InterfaceIndex)];
  424. cur = HashList->Flink;
  425. // Walk the list
  426. while (cur!=HashList) {
  427. ifCB = CONTAINING_RECORD(cur, INTERFACE_CB, ICB_IndexHashLink);
  428. if (ifCB->ICB_Index==InterfaceIndex)
  429. // Found, return it (insertion point is irrelevant)
  430. return ifCB;
  431. else if (ifCB->ICB_Index>InterfaceIndex)
  432. // No chance to find it
  433. break;
  434. cur = cur->Flink;
  435. }
  436. // Return insertion point if asked
  437. if (ARGUMENT_PRESENT(insertBefore))
  438. *insertBefore = cur;
  439. return NULL;
  440. }
  441. /*++
  442. *******************************************************************
  443. L o c a t e C l i e n t I n t e r f a c e
  444. Routine Description:
  445. Finds interface control block in client
  446. node hash bucket. Optionally returns the
  447. insertion point pointer if interface block
  448. with given node is not in the table
  449. Arguments:
  450. ClientNode - node address of the client on global network
  451. insertBefore - buffer to place the pointer to
  452. hash table element where interface
  453. block should be inserted if it is not
  454. already in the table
  455. Return Value:
  456. Pointer to interface control block if found
  457. NULL otherwise
  458. *******************************************************************
  459. --*/
  460. PINTERFACE_CB
  461. LocateClientInterface (
  462. ULONGLONG *NodeAddress64,
  463. PINTERFACE_CB **prevLink OPTIONAL
  464. ) {
  465. PINTERFACE_CB cur, *prev;
  466. prev = &ClientNodeHash[ClientNodeHashFunc (*NodeAddress64)];
  467. cur = *prev;
  468. while (cur!=NULL) {
  469. if (*NodeAddress64==cur->ICB_ClientNode64[0])
  470. break;
  471. else if (*NodeAddress64>cur->ICB_ClientNode64[0]) {
  472. // No chance to find it
  473. cur = NULL;
  474. break;
  475. }
  476. prev = &cur->ICB_NodeHashLink;
  477. cur = cur->ICB_NodeHashLink;
  478. }
  479. if (ARGUMENT_PRESENT(prevLink))
  480. *prevLink = prev;
  481. return cur;
  482. }
  483. /*++
  484. *******************************************************************
  485. L o c a t e R o u t e
  486. Routine Description:
  487. Finds route block in network number
  488. hash table. Optionally returns the
  489. insertion point pointer if route
  490. for given destination netowrk is not in the table
  491. Arguments:
  492. Network - destination netowork number
  493. insertBefore - buffer to place the pointer to
  494. hash table element where route
  495. block should be inserted if it is not
  496. already in the table
  497. Return Value:
  498. Pointer to route block if found
  499. NULL otherwise
  500. *******************************************************************
  501. --*/
  502. PFWD_ROUTE
  503. LocateRoute (
  504. ULONG Network,
  505. PFWD_ROUTE **prevLink OPTIONAL
  506. ) {
  507. PFWD_ROUTE cur, *prev;
  508. prev = &RouteHash[NetworkNumberHashFunc(Network)];
  509. cur = *prev;
  510. while (cur!=NULL) {
  511. if (cur->FR_Network==Network)
  512. break;
  513. else if (cur->FR_Network>Network) {
  514. cur = NULL;
  515. // No chance to find it
  516. break;
  517. }
  518. prev = &cur->FR_Next;
  519. cur = *prev;
  520. }
  521. if (ARGUMENT_PRESENT(prevLink))
  522. *prevLink = prev;
  523. return cur;
  524. }
  525. /*++
  526. *******************************************************************
  527. L o c a t e N B R o u t e
  528. Routine Description:
  529. Finds nb route block in nb name
  530. hash table. Optionally returns the
  531. insertion point pointer if nb route
  532. for given name is not in the table
  533. Arguments:
  534. Name - netbios name
  535. insertBefore - buffer to place the pointer to
  536. hash table element where route
  537. block should be inserted if it is not
  538. already in the table
  539. Return Value:
  540. Pointer to nb route block if found
  541. NULL otherwise
  542. *******************************************************************
  543. --*/
  544. PNB_ROUTE
  545. LocateNBRoute (
  546. ULONGLONG *Name128,
  547. PNB_ROUTE **prevLink OPTIONAL
  548. ) {
  549. PNB_ROUTE cur, *prev;
  550. prev = &NBRouteHash[NetbiosNameHashFunc(Name128)];
  551. cur = *prev;
  552. while (cur!=NULL) {
  553. if ((cur->NBR_Name128[0]==Name128[0])
  554. && (cur->NBR_Name128[1]==Name128[1]))
  555. break;
  556. else if ((cur->NBR_Name128[0]>Name128[0])
  557. || ((cur->NBR_Name128[0]==Name128[0])
  558. && (cur->NBR_Name128[1]>Name128[1]))) {
  559. cur = NULL;
  560. // No chance to find it
  561. break;
  562. }
  563. prev = &cur->NBR_Next;
  564. cur = *prev;
  565. }
  566. if (ARGUMENT_PRESENT(prevLink))
  567. *prevLink = prev;
  568. return cur;
  569. }
  570. /*++
  571. *******************************************************************
  572. G e t I n t e r f a c e R e f e r e n c e
  573. Routine Description:
  574. Returns reference interface based on its index
  575. Arguments:
  576. InterfaceIndex - unique id of the interface
  577. Return Value:
  578. Pointer to interface control block if there is one in the table
  579. NULL otherwise
  580. *******************************************************************
  581. --*/
  582. PINTERFACE_CB
  583. GetInterfaceReference (
  584. ULONG InterfaceIndex
  585. ) {
  586. KIRQL oldIRQL;
  587. PINTERFACE_CB ifCB;
  588. KeAcquireSpinLock (&InterfaceTableLock, &oldIRQL);
  589. if (InterfaceIndex!=FWD_INTERNAL_INTERFACE_INDEX)
  590. ifCB = LocateInterface (InterfaceIndex, NULL);
  591. else
  592. ifCB = InternalInterface;
  593. if (ifCB!=NULL) {
  594. AcquireInterfaceReference (ifCB);
  595. //if (ifCB->ICB_Index > 1)
  596. //IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_WARNING,
  597. // ("IpxFwd: GetInterfaceReference: Aquired if #%ld (%ld) \n", ifCB->ICB_Index, ifCB->ICB_ReferenceCount));
  598. }
  599. else {
  600. IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_ERROR,
  601. ("IpxFwd: Could not get interface reference %ld.\n", InterfaceIndex));
  602. }
  603. KeReleaseSpinLock (&InterfaceTableLock, oldIRQL);
  604. return ifCB;
  605. }
  606. //
  607. // Function IncrementNicIds
  608. //
  609. // Increments the nic id of every nic in the interface table
  610. // whose id is greater than or equal to the given threshold.
  611. //
  612. NTSTATUS IncrementNicids (USHORT usThreshold) {
  613. KIRQL oldIRQL;
  614. PINTERFACE_CB ifCB;
  615. PLIST_ENTRY cur;
  616. PLIST_ENTRY HashList;
  617. ULONG i;
  618. IpxFwdDbgPrint (DBG_IPXBIND, DBG_INFORMATION,
  619. ("IpxFwd: Incrementing all nic id's >= %d", usThreshold));
  620. KeAcquireSpinLock (&InterfaceTableLock, &oldIRQL);
  621. // Walk through all of the hash buckets
  622. for (i = 0; i < InterfaceHashSize; i++) {
  623. HashList = &InterfaceIndexHash[i];
  624. cur = HashList->Flink;
  625. // Walk the list in this bucket updating as needed
  626. while (cur!=HashList) {
  627. ifCB = CONTAINING_RECORD(cur, INTERFACE_CB, ICB_IndexHashLink);
  628. if ((ifCB->ICB_NicId != INVALID_NIC_ID) && (ifCB->ICB_NicId >= usThreshold)) {
  629. IpxFwdDbgPrint (DBG_IPXBIND, DBG_INFORMATION,
  630. ("IpxFwd: Incrementing nic id %d", ifCB->ICB_NicId));
  631. ifCB->ICB_NicId++;
  632. *((USHORT*)&ifCB->ICB_AdapterContext) = ifCB->ICB_NicId;
  633. }
  634. cur = cur->Flink;
  635. }
  636. }
  637. KeReleaseSpinLock (&InterfaceTableLock, oldIRQL);
  638. return STATUS_SUCCESS;
  639. }
  640. //
  641. // Function DecrementNicIds
  642. //
  643. // Decrements the nic id of every nic in the interface table
  644. // whose id is greater than the given threshold.
  645. //
  646. NTSTATUS DecrementNicids (USHORT usThreshold) {
  647. KIRQL oldIRQL;
  648. PINTERFACE_CB ifCB;
  649. PLIST_ENTRY cur;
  650. PLIST_ENTRY HashList;
  651. ULONG i;
  652. IpxFwdDbgPrint (DBG_IPXBIND, DBG_INFORMATION,
  653. ("IpxFwd: Decrementing all nic id's > %d", usThreshold));
  654. KeAcquireSpinLock (&InterfaceTableLock, &oldIRQL);
  655. // Walk through all of the hash buckets
  656. for (i = 0; i < InterfaceHashSize; i++) {
  657. HashList = &InterfaceIndexHash[i];
  658. cur = HashList->Flink;
  659. // Walk the list in this bucket updating as needed
  660. while (cur!=HashList) {
  661. ifCB = CONTAINING_RECORD(cur, INTERFACE_CB, ICB_IndexHashLink);
  662. // If this is a bound interface
  663. if (ifCB->ICB_NicId != INVALID_NIC_ID) {
  664. // If it's bound to a nic greater than the threshold, update
  665. // the nicid
  666. if (ifCB->ICB_NicId > usThreshold) {
  667. IpxFwdDbgPrint (DBG_IPXBIND, DBG_INFORMATION,
  668. ("IpxFwd: Decrementing nic id %d", ifCB->ICB_NicId));
  669. ifCB->ICB_NicId--;
  670. }
  671. // The if with bound to the threshold is now unbound.
  672. else if (ifCB->ICB_NicId == usThreshold) {
  673. IpxFwdDbgPrint (DBG_IPXBIND, DBG_INFORMATION,
  674. ("IpxFwd: Marking interface %d as unbound", ifCB->ICB_Index));
  675. ifCB->ICB_NicId = INVALID_NIC_ID;
  676. }
  677. *((USHORT*)&ifCB->ICB_AdapterContext) = ifCB->ICB_NicId;
  678. }
  679. cur = cur->Flink;
  680. }
  681. }
  682. KeReleaseSpinLock (&InterfaceTableLock, oldIRQL);
  683. return STATUS_SUCCESS;
  684. }
  685. //
  686. // Puts as much of the interface table into the buffer pointed to by
  687. // pRows as there is space.
  688. //
  689. NTSTATUS DoGetIfTable (FWD_INTERFACE_TABLE * pTable,
  690. ULONG dwRowBufferSize)
  691. {
  692. KIRQL oldIRQL;
  693. PINTERFACE_CB ifCB;
  694. PLIST_ENTRY cur;
  695. PLIST_ENTRY HashList;
  696. ULONG i, j = 0;
  697. KeAcquireSpinLock (&InterfaceTableLock, &oldIRQL);
  698. // Walk through all of the hash buckets
  699. for (i = 0; i < InterfaceHashSize; i++) {
  700. HashList = &InterfaceIndexHash[i];
  701. cur = HashList->Flink;
  702. // Walk the list in this bucket updating as needed
  703. while (cur!=HashList) {
  704. ifCB = CONTAINING_RECORD(cur, INTERFACE_CB, ICB_IndexHashLink);
  705. // Validate the size of the return buffer
  706. if (dwRowBufferSize <
  707. (sizeof(FWD_INTERFACE_TABLE) +
  708. (sizeof(FWD_INTERFACE_TABLE_ROW) * (j + 1))))
  709. {
  710. break;
  711. }
  712. // Validate the number of rows
  713. if (j >= pTable->dwNumRows)
  714. break;
  715. // Copy over the interface information
  716. pTable->pRows[j].dwIndex = ifCB->ICB_Index;
  717. pTable->pRows[j].dwNetwork = ifCB->ICB_Network;
  718. memcpy (pTable->pRows[j].uNode, ifCB->ICB_LocalNode, 6);
  719. memcpy (pTable->pRows[j].uRemoteNode, ifCB->ICB_RemoteNode, 6);
  720. pTable->pRows[j].usNicId = ifCB->ICB_NicId;
  721. pTable->pRows[j].ucType = ifCB->ICB_InterfaceType;
  722. j++;
  723. // Advance the current row and interface
  724. cur = cur->Flink;
  725. }
  726. }
  727. KeReleaseSpinLock (&InterfaceTableLock, oldIRQL);
  728. pTable->dwNumRows = j;
  729. return STATUS_SUCCESS;
  730. }
  731. /*++
  732. *******************************************************************
  733. G e t N e x t I n t e r f a c e R e f e r e n c e
  734. Routine Description:
  735. Returns reference to the next interface in the table
  736. Reference to the provided interface is released
  737. Arguments:
  738. ifCB - interface to start with or NULL to start from the
  739. beginning of the interface table
  740. Return Value:
  741. Pointer to interface control block if thare are any more interfaces
  742. in the table
  743. NULL otherwise
  744. *******************************************************************
  745. --*/
  746. PINTERFACE_CB
  747. GetNextInterfaceReference (
  748. PINTERFACE_CB ifCB
  749. ) {
  750. PLIST_ENTRY cur;
  751. PLIST_ENTRY HashList;
  752. KIRQL oldIRQL;
  753. KeAcquireSpinLock (&InterfaceTableLock, &oldIRQL);
  754. if (ifCB!=NULL) {
  755. // Find hash bucket
  756. ASSERT (ifCB->ICB_Index!=FWD_INTERNAL_INTERFACE_INDEX);
  757. HashList = &InterfaceIndexHash[InterfaceIndexHashFunc(ifCB->ICB_Index)];
  758. if (LocateInterface (ifCB->ICB_Index, &cur)!=NULL)
  759. cur = ifCB->ICB_IndexHashLink.Flink;
  760. ReleaseInterfaceReference (ifCB);
  761. ifCB = NULL;
  762. }
  763. else
  764. cur = HashList = InterfaceIndexHash-1;
  765. if (cur==HashList) {
  766. do {
  767. HashList += 1;
  768. if (HashList==&InterfaceIndexHash[InterfaceHashSize]) {
  769. KeReleaseSpinLock (&InterfaceTableLock, oldIRQL);
  770. return NULL;
  771. }
  772. } while (IsListEmpty (HashList));
  773. cur = HashList->Flink;
  774. }
  775. ifCB = CONTAINING_RECORD (cur, INTERFACE_CB, ICB_IndexHashLink);
  776. AcquireInterfaceReference (ifCB);
  777. KeReleaseSpinLock (&InterfaceTableLock, oldIRQL);
  778. return ifCB;
  779. }
  780. /*++
  781. *******************************************************************
  782. A d d I n t e r f a c e
  783. Routine Description:
  784. Adds interface control block to the table.
  785. Arguments:
  786. InterfaceIndex - unique if of the interface
  787. Info - interface paramters
  788. Return Value:
  789. STATUS_SUCCESS - interface added ok
  790. STATUS_UNSUCCESSFUL - interface is already in the table
  791. STATUS_INSUFFICIENT_RESOURCES - can't allocate memory for
  792. interface CB
  793. *******************************************************************
  794. --*/
  795. NTSTATUS
  796. AddInterface (
  797. ULONG InterfaceIndex,
  798. UCHAR InterfaceType,
  799. BOOLEAN NetbiosAccept,
  800. UCHAR NetbiosDeliver
  801. ) {
  802. PINTERFACE_CB ifCB;
  803. PLIST_ENTRY cur;
  804. KIRQL oldIRQL;
  805. NTSTATUS status = STATUS_SUCCESS;
  806. KeAcquireSpinLock (&InterfaceTableLock, &oldIRQL);
  807. if (InterfaceIndex!=FWD_INTERNAL_INTERFACE_INDEX) {
  808. ifCB = LocateInterface (InterfaceIndex, &cur);
  809. if (ifCB==NULL) {
  810. ifCB = AllocateInterface ();
  811. if (ifCB!=NULL)
  812. NOTHING;
  813. else {
  814. status = STATUS_INSUFFICIENT_RESOURCES;
  815. goto AddEnd;
  816. }
  817. }
  818. else {
  819. IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_ERROR,
  820. ("IpxFwd: Interface %ld is already in the table!\n", InterfaceIndex));
  821. status = STATUS_UNSUCCESSFUL;
  822. goto AddEnd;
  823. }
  824. }
  825. else
  826. ifCB = InternalInterface;
  827. InitICB (ifCB, InterfaceIndex,InterfaceType,NetbiosAccept,NetbiosDeliver);
  828. #if DBG
  829. InitializeListHead (&ifCB->ICB_InSendQueue);
  830. #endif
  831. switch (InterfaceType) {
  832. case FWD_IF_PERMANENT:
  833. break;
  834. case FWD_IF_DEMAND_DIAL:
  835. case FWD_IF_LOCAL_WORKSTATION:
  836. case FWD_IF_REMOTE_WORKSTATION:
  837. ASSERT (InterfaceIndex!=FWD_INTERNAL_INTERFACE_INDEX);
  838. if (WanPacketListId==-1) {
  839. status = RegisterPacketConsumer (
  840. WAN_PACKET_SIZE,
  841. &WanPacketListId);
  842. if (!NT_SUCCESS (status)) {
  843. WanPacketListId = -1;
  844. break;
  845. }
  846. }
  847. ifCB->ICB_PacketListId = WanPacketListId;
  848. break;
  849. }
  850. if (NT_SUCCESS (status)) {
  851. if (InterfaceIndex!=FWD_INTERNAL_INTERFACE_INDEX) {
  852. InsertTailList (cur, &ifCB->ICB_IndexHashLink);
  853. }
  854. IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_WARNING,
  855. ("IpxFwd: Adding interface %d (icb: %08lx, plid: %d)\n",
  856. InterfaceIndex, ifCB, ifCB->ICB_PacketListId));
  857. }
  858. else
  859. FreeInterface (ifCB);
  860. AddEnd:
  861. KeReleaseSpinLock (&InterfaceTableLock, oldIRQL);
  862. return status;
  863. }
  864. /*++
  865. *******************************************************************
  866. A d d G l o b a l N e t C l i e n t
  867. Routine Description:
  868. Adds interface control block to the table of
  869. clients on the global network (should be done when
  870. client connects)
  871. Arguments:
  872. ifCB - interface control block to add to the table
  873. Return Value:
  874. STATUS_SUCCESS - interface was added ok
  875. STATUS_UNSUCCESSFUL - another interface with the same
  876. node address is already in the table
  877. *******************************************************************
  878. --*/
  879. NTSTATUS
  880. AddGlobalNetClient (
  881. PINTERFACE_CB ifCB
  882. ) {
  883. KIRQL oldIRQL;
  884. RWCOOKIE cookie;
  885. PINTERFACE_CB *prev;
  886. NTSTATUS status = STATUS_SUCCESS;
  887. ASSERT (ifCB->ICB_Index!=FWD_INTERNAL_INTERFACE_INDEX);
  888. AcquireReaderAccess (&RWLock, cookie);
  889. KeAcquireSpinLock (&InterfaceTableLock, &oldIRQL);
  890. if (LocateClientInterface (ifCB->ICB_ClientNode64, &prev)==NULL) {
  891. ifCB->ICB_NodeHashLink = *prev;
  892. *prev = ifCB;
  893. KeReleaseSpinLock (&InterfaceTableLock, oldIRQL);
  894. ReleaseReaderAccess (&RWLock, cookie);
  895. AcquireInterfaceReference (ifCB); // To make sure that
  896. // interface block does not
  897. // get deleted until it is
  898. // removed from the node table
  899. IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_WARNING,
  900. ("IpxFwd: Adding interface %ld (icb: %08lx, ref=%ld)"
  901. " to global client table.\n", ifCB->ICB_Index, ifCB->ICB_ReferenceCount, ifCB));
  902. }
  903. else {
  904. KeReleaseSpinLock (&InterfaceTableLock, oldIRQL);
  905. ReleaseReaderAccess (&RWLock, cookie);
  906. IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_ERROR,
  907. ("IpxFwd: Interface %ld (icb: %08lx)"
  908. " is already in the global client table.\n",
  909. ifCB->ICB_Index, ifCB));
  910. status = STATUS_UNSUCCESSFUL;
  911. }
  912. return status;
  913. }
  914. /*++
  915. *******************************************************************
  916. D e l e t e G l o b a l N e t C l i e n t
  917. Routine Description:
  918. Removes interface control block from the table of
  919. clients on the global network (should be done when
  920. client disconnects)
  921. Arguments:
  922. ifCB - interface control block to remove from the table
  923. Return Value:
  924. STATUS_SUCCESS - interface was removed ok
  925. *******************************************************************
  926. --*/
  927. NTSTATUS
  928. DeleteGlobalNetClient (
  929. PINTERFACE_CB ifCB
  930. ) {
  931. KIRQL oldIRQL;
  932. RWCOOKIE cookie;
  933. PINTERFACE_CB cur, *prev;
  934. IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_WARNING,
  935. ("IpxFwd: Deleting interface %ld (icb: %08lx)"
  936. " from global client table.\n", ifCB->ICB_Index, ifCB));
  937. ASSERT (ifCB->ICB_Index!=FWD_INTERNAL_INTERFACE_INDEX);
  938. AcquireReaderAccess (&RWLock, cookie);
  939. KeAcquireSpinLock (&InterfaceTableLock, &oldIRQL);
  940. cur = LocateClientInterface (ifCB->ICB_ClientNode64, &prev);
  941. ASSERT (cur==ifCB);
  942. *prev = ifCB->ICB_NodeHashLink;
  943. KeReleaseSpinLock (&InterfaceTableLock, oldIRQL);
  944. ReleaseReaderAccess (&RWLock, cookie);
  945. ReleaseInterfaceReference (ifCB);
  946. return STATUS_SUCCESS;
  947. }
  948. /*++
  949. *******************************************************************
  950. D e l e t e I n t e r f a c e
  951. Routine Description:
  952. Deletes interface control block (the block is not actually
  953. disposed of until all references to it are released).
  954. Arguments:
  955. InterfaceIndex - unique if of the interface
  956. Return Value:
  957. STATUS_SUCCESS - interface info retreived ok
  958. STATUS_UNSUCCESSFUL - interface is not in the table
  959. *******************************************************************
  960. --*/
  961. NTSTATUS
  962. DeleteInterface (
  963. ULONG InterfaceIndex
  964. ) {
  965. PINTERFACE_CB ifCB;
  966. KIRQL oldIRQL;
  967. NTSTATUS status = STATUS_SUCCESS;
  968. KeAcquireSpinLock (&InterfaceTableLock, &oldIRQL);
  969. if (InterfaceIndex!=FWD_INTERNAL_INTERFACE_INDEX)
  970. ifCB = LocateInterface (InterfaceIndex, NULL);
  971. else
  972. ifCB = InternalInterface;
  973. if (ifCB!=NULL) {
  974. if (InterfaceIndex!=FWD_INTERNAL_INTERFACE_INDEX) {
  975. RemoveEntryList (&ifCB->ICB_IndexHashLink);
  976. }
  977. KeReleaseSpinLock (&InterfaceTableLock, oldIRQL);
  978. if (ifCB->ICB_Stats.OperationalState == FWD_OPER_STATE_UP) {
  979. IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_ERROR,
  980. ("IpxFwd: Interface %ld (icb: %08lx) was still bound"
  981. " when asked to delete it.\n",
  982. ifCB->ICB_Index, ifCB));
  983. UnbindInterface (ifCB);
  984. }
  985. else if (IS_IF_CONNECTING (ifCB)) {
  986. IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_ERROR,
  987. ("IpxFwd: Interface %ld (icb: %08lx) was still being connected"
  988. " when asked to delete it.\n",
  989. ifCB->ICB_Index, ifCB));
  990. SET_IF_NOT_CONNECTING (ifCB);
  991. DequeueConnectionRequest (ifCB);
  992. ProcessInternalQueue (ifCB);
  993. ProcessExternalQueue (ifCB);
  994. }
  995. ifCB->ICB_Stats.OperationalState = FWD_OPER_STATE_DOWN;
  996. IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_WARNING,
  997. ("IpxFwd: Deleting interface %ld (icb: %08lx).\n",
  998. ifCB->ICB_Index, ifCB));
  999. if (ifCB->ICB_NBRoutes!=NULL) {
  1000. DeleteNBRoutes (ifCB->ICB_NBRoutes, ifCB->ICB_NBRouteCount);
  1001. ifCB->ICB_NBRoutes = NULL;
  1002. }
  1003. FltInterfaceDeleted (ifCB);
  1004. ReleaseInterfaceReference (ifCB);
  1005. }
  1006. else {
  1007. KeReleaseSpinLock (&InterfaceTableLock, oldIRQL);
  1008. IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_ERROR,
  1009. ("IpxFwd: Could not delete interface %ld because it is not found.\n",
  1010. InterfaceIndex));
  1011. status = STATUS_UNSUCCESSFUL;
  1012. }
  1013. return status;
  1014. }
  1015. /*++
  1016. *******************************************************************
  1017. A d d R o u t e
  1018. Routine Description:
  1019. Adds route to the hash table and finds and stores the reference
  1020. to the associated interface control block in the route.
  1021. Arguments:
  1022. Network - route's destination network
  1023. NextHopAddress - mac address of next hop router if network is not
  1024. directly connected
  1025. TickCount - ticks to reach the destination net
  1026. HopCount - hopss to reach the destination net
  1027. InterfaceIndex - index of the associated interface (through which
  1028. packets destined to the network are to be sent)
  1029. Return Value:
  1030. STATUS_SUCCESS - route was added ok
  1031. STATUS_UNSUCCESSFUL - route is already in the table
  1032. STATUS_INSUFFICIENT_RESOURCES - can't allocate memory for
  1033. route block
  1034. *******************************************************************
  1035. --*/
  1036. NTSTATUS
  1037. AddRoute (
  1038. ULONG Network,
  1039. UCHAR *NextHopAddress,
  1040. USHORT TickCount,
  1041. USHORT HopCount,
  1042. ULONG InterfaceIndex
  1043. ) {
  1044. PFWD_ROUTE fwRoute;
  1045. PFWD_ROUTE *prev;
  1046. NTSTATUS status = STATUS_SUCCESS;
  1047. KIRQL oldIRQL;
  1048. // Assume success, allocate route and intialize it
  1049. // (the goal is to spend as little time as possible
  1050. // inside exclusive usage zone)
  1051. fwRoute = AllocateRoute ();
  1052. if (fwRoute!=NULL) {
  1053. fwRoute->FR_Network = Network;
  1054. IPX_NODE_CPY (fwRoute->FR_NextHopAddress, NextHopAddress);
  1055. fwRoute->FR_TickCount = TickCount;
  1056. fwRoute->FR_HopCount = HopCount;
  1057. fwRoute->FR_ReferenceCount = 0;
  1058. if (InterfaceIndex!=0xFFFFFFFF) {
  1059. // See if interface is there
  1060. KeAcquireSpinLock (&InterfaceTableLock, &oldIRQL);
  1061. if (InterfaceIndex!=FWD_INTERNAL_INTERFACE_INDEX)
  1062. fwRoute->FR_InterfaceReference
  1063. = LocateInterface (InterfaceIndex, NULL);
  1064. else
  1065. fwRoute->FR_InterfaceReference = InternalInterface;
  1066. if (fwRoute->FR_InterfaceReference!=NULL) {
  1067. AcquireInterfaceReference (fwRoute->FR_InterfaceReference);
  1068. //if (fwRoute->FR_InterfaceReference->ICB_Index > 1)
  1069. //IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_WARNING,
  1070. // ("IpxFwd: AddRoute: Aquired if #%ld (%ld) \n",
  1071. // fwRoute->FR_InterfaceReference->ICB_Index,
  1072. // fwRoute->FR_InterfaceReference->ICB_ReferenceCount));
  1073. KeReleaseSpinLock (&InterfaceTableLock, oldIRQL);
  1074. ExAcquireFastMutex (&WriterMutex);
  1075. // Check if route is already there
  1076. if (LocateRoute (Network, &prev)==NULL) {
  1077. fwRoute->FR_Next = *prev;
  1078. *prev = fwRoute;
  1079. }
  1080. else {
  1081. ReleaseInterfaceReference (fwRoute->FR_InterfaceReference);
  1082. fwRoute->FR_InterfaceReference = NULL;
  1083. IpxFwdDbgPrint (DBG_ROUTE_TABLE, DBG_ERROR,
  1084. ("IpxFwd: Route for net %08lx"
  1085. " is already in the table!\n", Network));
  1086. status = STATUS_UNSUCCESSFUL;
  1087. }
  1088. ExReleaseFastMutex (&WriterMutex);
  1089. }
  1090. else {
  1091. KeReleaseSpinLock (&InterfaceTableLock, oldIRQL);
  1092. IpxFwdDbgPrint (DBG_ROUTE_TABLE, DBG_ERROR,
  1093. ("IpxFwd: Interface %ld for route for net %08lx"
  1094. " is not in the table!\n", InterfaceIndex, Network));
  1095. status = STATUS_UNSUCCESSFUL;
  1096. }
  1097. }
  1098. else {
  1099. ExAcquireFastMutex (&WriterMutex);
  1100. // Just check if we do not have it already
  1101. if (GlobalRoute==NULL) {
  1102. fwRoute->FR_InterfaceReference = GLOBAL_INTERFACE_REFERENCE;
  1103. GlobalNetwork = Network;
  1104. GlobalRoute = fwRoute;
  1105. }
  1106. else {
  1107. IpxFwdDbgPrint (DBG_ROUTE_TABLE, DBG_ERROR,
  1108. ("IpxFwd: Route for global net %08lx"
  1109. " is already in the table!\n", Network));
  1110. status = STATUS_UNSUCCESSFUL;
  1111. }
  1112. ExReleaseFastMutex (&WriterMutex);
  1113. }
  1114. if (NT_SUCCESS (status)) {
  1115. IpxFwdDbgPrint (DBG_ROUTE_TABLE, DBG_WARNING,
  1116. ("IpxFwd: Adding route for net %08lx"
  1117. " (rb: %08lx, NHA: %02x%02x%02x%02x%02x%02x,"
  1118. " if: %ld, icb: %08lx).\n",
  1119. Network, fwRoute,
  1120. NextHopAddress[0], NextHopAddress[1],
  1121. NextHopAddress[2], NextHopAddress[3],
  1122. NextHopAddress[4], NextHopAddress[5],
  1123. InterfaceIndex, fwRoute->FR_InterfaceReference));
  1124. }
  1125. else {
  1126. FreeRoute (fwRoute);
  1127. }
  1128. }
  1129. else
  1130. status = STATUS_INSUFFICIENT_RESOURCES;
  1131. return status;
  1132. }
  1133. /*++
  1134. *******************************************************************
  1135. D e l e t e R o u t e
  1136. Routine Description:
  1137. Deletes route from the hash table and releases the reference
  1138. to the interface control block associated with the route.
  1139. Arguments:
  1140. Network - route's destination network
  1141. Return Value:
  1142. STATUS_SUCCESS - route was deleted ok
  1143. STATUS_UNSUCCESSFUL - route is not in the table
  1144. *******************************************************************
  1145. --*/
  1146. NTSTATUS
  1147. DeleteRoute (
  1148. ULONG Network
  1149. ) {
  1150. PFWD_ROUTE fwRoute, *prev;
  1151. NTSTATUS status = STATUS_SUCCESS;
  1152. ExAcquireFastMutex (&WriterMutex);
  1153. if ((GlobalRoute!=NULL)
  1154. && (GlobalNetwork==Network)) {
  1155. fwRoute = GlobalRoute;
  1156. GlobalNetwork = 0xFFFFFFFF;
  1157. GlobalRoute = NULL;
  1158. }
  1159. else if ((fwRoute=LocateRoute (Network, &prev))!=NULL) {
  1160. *prev = fwRoute->FR_Next;
  1161. }
  1162. if (fwRoute!=NULL) {
  1163. IpxFwdDbgPrint (DBG_ROUTE_TABLE, DBG_WARNING,
  1164. ("IpxFwd: Deleting route for net %08lx (rb: %08lx).\n",
  1165. Network, fwRoute));
  1166. WaitForAllReaders (&RWLock);
  1167. if (fwRoute->FR_InterfaceReference!=GLOBAL_INTERFACE_REFERENCE) {
  1168. ReleaseInterfaceReference (fwRoute->FR_InterfaceReference);
  1169. }
  1170. fwRoute->FR_InterfaceReference = NULL;
  1171. ReleaseRouteReference (fwRoute);
  1172. }
  1173. else {
  1174. IpxFwdDbgPrint (DBG_ROUTE_TABLE, DBG_ERROR,
  1175. ("IpxFwd: Could not delete route for net %08lx because it is not in the table.\n",
  1176. Network));
  1177. status = STATUS_UNSUCCESSFUL;
  1178. }
  1179. ExReleaseFastMutex (&WriterMutex);
  1180. return status;
  1181. }
  1182. /*++
  1183. *******************************************************************
  1184. U p d a t e R o u t e
  1185. Routine Description:
  1186. Updates route in the hash table
  1187. Arguments:
  1188. Network - route's destination network
  1189. NextHopAddress - mac address of next hop router if network is not
  1190. directly connected
  1191. TickCount - ticks to reach the destination net
  1192. HopCount - hopss to reach the destination net
  1193. InterfaceIndex - index of the associated interface (through which
  1194. packets destined to the network are to be sent)
  1195. Return Value:
  1196. STATUS_SUCCESS - interface info retreived ok
  1197. STATUS_UNSUCCESSFUL - interface is not in the table
  1198. *******************************************************************
  1199. --*/
  1200. NTSTATUS
  1201. UpdateRoute (
  1202. ULONG Network,
  1203. UCHAR *NextHopAddress,
  1204. USHORT TickCount,
  1205. USHORT HopCount,
  1206. ULONG InterfaceIndex
  1207. ) {
  1208. PFWD_ROUTE fwRoute = NULL, newRoute, *prev;
  1209. PINTERFACE_CB ifCB = NULL;
  1210. KIRQL oldIRQL;
  1211. NTSTATUS status = STATUS_SUCCESS;
  1212. ExAcquireFastMutex (&WriterMutex);
  1213. if ((GlobalRoute!=NULL)
  1214. && (GlobalNetwork==Network)) {
  1215. InterfaceIndex = 0xFFFFFFFF;
  1216. fwRoute = GlobalRoute;
  1217. }
  1218. else {
  1219. ASSERT (InterfaceIndex!=0xFFFFFFFF);
  1220. fwRoute = LocateRoute (Network, &prev);
  1221. if ((fwRoute != NULL) && (fwRoute->FR_InterfaceReference == GLOBAL_INTERFACE_REFERENCE))
  1222. {
  1223. status = STATUS_UNSUCCESSFUL;
  1224. goto ExitUpdate;
  1225. }
  1226. }
  1227. if (fwRoute!=NULL) {
  1228. if (InterfaceIndex!=0xFFFFFFFF) {
  1229. if (fwRoute->FR_InterfaceReference->ICB_Index!=InterfaceIndex) {
  1230. // Get a reference to new interface
  1231. KeAcquireSpinLock (&InterfaceTableLock, &oldIRQL);
  1232. if (InterfaceIndex!=FWD_INTERNAL_INTERFACE_INDEX)
  1233. ifCB = LocateInterface (InterfaceIndex, NULL);
  1234. else
  1235. ifCB = InternalInterface;
  1236. if (ifCB!=NULL) {
  1237. AcquireInterfaceReference (ifCB);
  1238. //if (ifCB->ICB_Index > 1)
  1239. //IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_WARNING,
  1240. // ("IpxFwd: UpdateRoute: Aquired if #%ld (%ld) \n", ifCB->ICB_Index, ifCB->ICB_ReferenceCount));
  1241. }
  1242. else {
  1243. KeReleaseSpinLock (&InterfaceTableLock, oldIRQL);
  1244. status = STATUS_UNSUCCESSFUL;
  1245. goto ExitUpdate;
  1246. }
  1247. KeReleaseSpinLock (&InterfaceTableLock, oldIRQL);
  1248. }
  1249. else {
  1250. ifCB = fwRoute->FR_InterfaceReference;
  1251. AcquireInterfaceReference (ifCB);
  1252. //if (ifCB->ICB_Index > 1)
  1253. //IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_WARNING,
  1254. // ("IpxFwd: UpdateRoute(2): Aquired if #%ld (%ld) \n", ifCB->ICB_Index, ifCB->ICB_ReferenceCount));
  1255. }
  1256. }
  1257. else
  1258. ifCB = GLOBAL_INTERFACE_REFERENCE;
  1259. newRoute = AllocateRoute ();
  1260. if (newRoute!=NULL) {
  1261. newRoute->FR_Network = Network;
  1262. IPX_NODE_CPY (newRoute->FR_NextHopAddress, NextHopAddress);
  1263. newRoute->FR_TickCount = TickCount;
  1264. newRoute->FR_HopCount = HopCount;
  1265. newRoute->FR_ReferenceCount = 0;
  1266. newRoute->FR_InterfaceReference = ifCB;
  1267. // Lock the table only when updating it
  1268. if (InterfaceIndex!=0xFFFFFFFF) {
  1269. newRoute->FR_Next = fwRoute->FR_Next;
  1270. *prev = newRoute;
  1271. }
  1272. else
  1273. GlobalRoute = newRoute;
  1274. WaitForAllReaders (&RWLock)
  1275. if (fwRoute->FR_InterfaceReference!=GLOBAL_INTERFACE_REFERENCE) {
  1276. ReleaseInterfaceReference (fwRoute->FR_InterfaceReference);
  1277. }
  1278. fwRoute->FR_InterfaceReference = NULL;
  1279. ReleaseRouteReference (fwRoute);
  1280. }
  1281. else
  1282. status = STATUS_INSUFFICIENT_RESOURCES;
  1283. }
  1284. else
  1285. status = STATUS_UNSUCCESSFUL;
  1286. ExitUpdate:
  1287. ExReleaseFastMutex (&WriterMutex);
  1288. return status;
  1289. }
  1290. /*++
  1291. *******************************************************************
  1292. F i n d D e s t i n a t i o n
  1293. Routine Description:
  1294. Finds destination interface for IPX address and
  1295. returns reference to its control block.
  1296. Arguments:
  1297. Network - destination network
  1298. Node - destination node (needed in case of global client)
  1299. Route - buffer to hold reference to route block
  1300. Return Value:
  1301. Reference to destination interface CB
  1302. NULL if route it not found
  1303. *******************************************************************
  1304. --*/
  1305. PINTERFACE_CB
  1306. FindDestination (
  1307. IN ULONG Network,
  1308. IN PUCHAR Node,
  1309. OUT PFWD_ROUTE *Route
  1310. ) {
  1311. PFWD_ROUTE fwRoute;
  1312. PINTERFACE_CB ifCB;
  1313. RWCOOKIE cookie;
  1314. AcquireReaderAccess (&RWLock, cookie);
  1315. if ((GlobalRoute!=NULL)
  1316. && (GlobalNetwork==Network)) {
  1317. if (Node!=NULL) { // If caller did not specify node,
  1318. // we can't find the route
  1319. union {
  1320. ULONGLONG Node64[1];
  1321. UCHAR Node[6];
  1322. } u;
  1323. u.Node64[0] = 0;
  1324. IPX_NODE_CPY (u.Node, Node);
  1325. ifCB = LocateClientInterface (u.Node64, NULL);
  1326. if (ifCB!=NULL) {
  1327. AcquireRouteReference (GlobalRoute);
  1328. *Route = GlobalRoute;
  1329. AcquireInterfaceReference (ifCB);
  1330. //if (ifCB->ICB_Index > 1)
  1331. //IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_WARNING,
  1332. // ("IpxFwd: FindDestination: Aquired if #%ld (%ld) \n", ifCB->ICB_Index, ifCB->ICB_ReferenceCount));
  1333. }
  1334. else
  1335. *Route = NULL;
  1336. }
  1337. else {
  1338. ifCB = NULL;
  1339. *Route = NULL;
  1340. }
  1341. }
  1342. else {
  1343. *Route = fwRoute = LocateRoute (Network, NULL);
  1344. if (fwRoute!=NULL) {
  1345. AcquireRouteReference (fwRoute);
  1346. ifCB = fwRoute->FR_InterfaceReference;
  1347. AcquireInterfaceReference (ifCB);
  1348. //if (ifCB->ICB_Index > 1)
  1349. //IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_WARNING,
  1350. // ("IpxFwd: FindDestination(2): Aquired if #%ld (%ld) \n", ifCB->ICB_Index, ifCB->ICB_ReferenceCount));
  1351. }
  1352. else
  1353. ifCB = NULL;
  1354. }
  1355. ReleaseReaderAccess (&RWLock, cookie);
  1356. return ifCB;
  1357. }
  1358. /*++
  1359. *******************************************************************
  1360. A d d N B R o u t e s
  1361. Routine Description:
  1362. Adds netbios names associated with interface to netbios
  1363. route hash table
  1364. Arguments:
  1365. ifCB - interface with which names are associated
  1366. Names - array of names
  1367. Count - number of names in the array
  1368. routeArray - buffer to place allocated array of routes
  1369. Return Value:
  1370. STATUS_SUCCESS - names were added ok
  1371. STATUS_UNSUCCESSFUL - one of the names is already in the table
  1372. STATUS_INSUFFICIENT_RESOURCES - can't allocate memory for
  1373. route array
  1374. *******************************************************************
  1375. --*/
  1376. NTSTATUS
  1377. AddNBRoutes (
  1378. PINTERFACE_CB ifCB,
  1379. FWD_NB_NAME Names[],
  1380. ULONG Count,
  1381. PNB_ROUTE *routeArray
  1382. ) {
  1383. PNB_ROUTE nbRoutes, *prev;
  1384. NTSTATUS status = STATUS_SUCCESS;
  1385. nbRoutes = (PNB_ROUTE)ExAllocatePoolWithTag (
  1386. NonPagedPool, sizeof (NB_ROUTE)*Count, FWD_POOL_TAG);
  1387. if (nbRoutes!=NULL) {
  1388. ULONG i;
  1389. ExAcquireFastMutex (&WriterMutex);
  1390. for (i=0; i<Count; i++) {
  1391. nbRoutes[i].NBR_Name128[0] = nbRoutes[i].NBR_Name128[1] = 0;
  1392. NB_NAME_CPY (nbRoutes[i].NBR_Name, &Names[i]);
  1393. // Check if route is already there
  1394. if (LocateNBRoute (nbRoutes[i].NBR_Name128, &prev)==NULL) {
  1395. nbRoutes[i].NBR_Destination = ifCB;
  1396. nbRoutes[i].NBR_Next = *prev;
  1397. *prev = &nbRoutes[i];
  1398. IpxFwdDbgPrint (DBG_NBROUTE_TABLE, DBG_WARNING,
  1399. ("IpxFwd: Adding nb route for name %16s.\n",Names[i]));
  1400. }
  1401. else {
  1402. IpxFwdDbgPrint (DBG_NBROUTE_TABLE, DBG_ERROR,
  1403. ("IpxFwd: Route for nb name %16s"
  1404. " is already in the table!\n", Names[i]));
  1405. break;
  1406. }
  1407. }
  1408. ExReleaseFastMutex (&WriterMutex);
  1409. if (i==Count) {
  1410. *routeArray = nbRoutes;
  1411. status = STATUS_SUCCESS;
  1412. }
  1413. else {
  1414. status = STATUS_UNSUCCESSFUL;
  1415. DeleteNBRoutes (nbRoutes, i);
  1416. }
  1417. }
  1418. else {
  1419. IpxFwdDbgPrint (DBG_NBROUTE_TABLE, DBG_ERROR,
  1420. ("IpxFwd: Could allocate nb route array for if: %ld"
  1421. " (icb: %08lx).\n", ifCB->ICB_Index, ifCB));
  1422. status = STATUS_INSUFFICIENT_RESOURCES;
  1423. }
  1424. return status;
  1425. }
  1426. /*++
  1427. *******************************************************************
  1428. D e l e t e N B R o u t e s
  1429. Routine Description:
  1430. Deletes nb routes in the array from the route table and frees
  1431. the array
  1432. Arguments:
  1433. nbRoutes - array of routes
  1434. Count - number of routes in the array
  1435. Return Value:
  1436. STATUS_SUCCESS - route was deleted ok
  1437. STATUS_UNSUCCESSFUL - route is not in the table
  1438. *******************************************************************
  1439. --*/
  1440. NTSTATUS
  1441. DeleteNBRoutes (
  1442. PNB_ROUTE nbRoutes,
  1443. ULONG Count
  1444. ) {
  1445. PNB_ROUTE *prev;
  1446. NTSTATUS status = STATUS_SUCCESS;
  1447. ULONG i;
  1448. ExAcquireFastMutex (&WriterMutex);
  1449. for (i=0; i<Count; i++) {
  1450. PNB_ROUTE cur = LocateNBRoute (nbRoutes[i].NBR_Name128, &prev);
  1451. ASSERT (cur==&nbRoutes[i]);
  1452. *prev = nbRoutes[i].NBR_Next;
  1453. IpxFwdDbgPrint (DBG_NBROUTE_TABLE, DBG_WARNING,
  1454. ("IpxFwd: Deleting nb route for name %16s.\n",
  1455. nbRoutes[i].NBR_Name));
  1456. }
  1457. WaitForAllReaders (&RWLock);
  1458. ExReleaseFastMutex (&WriterMutex);
  1459. ExFreePool (nbRoutes);
  1460. return STATUS_SUCCESS;
  1461. }
  1462. /*++
  1463. *******************************************************************
  1464. F i n d N B D e s t i n a t i o n
  1465. Routine Description:
  1466. Finds destination interface for nb name and
  1467. returns reference to its control block.
  1468. Arguments:
  1469. Name - name to look for
  1470. Return Value:
  1471. Reference to destination interface CB
  1472. NULL if route it not found
  1473. *******************************************************************
  1474. --*/
  1475. PINTERFACE_CB
  1476. FindNBDestination (
  1477. IN PUCHAR Name
  1478. ) {
  1479. PNB_ROUTE nbRoute;
  1480. PINTERFACE_CB ifCB;
  1481. RWCOOKIE cookie;
  1482. union {
  1483. ULONGLONG Name128[2];
  1484. UCHAR Name[16];
  1485. } u;
  1486. u.Name128[0] = u.Name128[1] = 0;
  1487. NB_NAME_CPY (u.Name, Name);
  1488. AcquireReaderAccess (&RWLock, cookie);
  1489. nbRoute = LocateNBRoute (u.Name128, NULL);
  1490. if (nbRoute!=NULL) {
  1491. ifCB = nbRoute->NBR_Destination;
  1492. AcquireInterfaceReference (ifCB);
  1493. //if (ifCB->ICB_Index > 1)
  1494. //IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_WARNING,
  1495. // ("IpxFwd: FindNBDestination: Aquired if #%ld (%ld) \n", ifCB->ICB_Index, ifCB->ICB_ReferenceCount));
  1496. }
  1497. else
  1498. ifCB = NULL;
  1499. ReleaseReaderAccess (&RWLock, cookie);
  1500. return ifCB;
  1501. }