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.

765 lines
16 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. node.c
  5. Abstract:
  6. This module contains the Appletalk Node management code.
  7. Author:
  8. Jameel Hyder (jameelh@microsoft.com)
  9. Nikhil Kamkolkar (nikhilk@microsoft.com)
  10. Revision History:
  11. 19 Jun 1992 Initial Version
  12. Notes: Tab stop: 4
  13. --*/
  14. #include <atalk.h>
  15. #pragma hdrstop
  16. #define FILENUM NODE
  17. #ifdef ALLOC_PRAGMA
  18. #pragma alloc_text(PAGEINIT, AtalkInitNodeCreateOnPort)
  19. #pragma alloc_text(PAGEINIT, AtalkInitNodeAllocate)
  20. #pragma alloc_text(PAGEINIT, AtalkInitNodeGetPramAddr)
  21. #pragma alloc_text(PAGEINIT, AtalkInitNodeSavePramAddr)
  22. #endif
  23. ATALK_ERROR
  24. AtalkInitNodeCreateOnPort(
  25. PPORT_DESCRIPTOR pPortDesc,
  26. BOOLEAN AllowStartupRange,
  27. BOOLEAN RouterNode,
  28. PATALK_NODEADDR NodeAddr
  29. )
  30. /*++
  31. Routine Description:
  32. Arguments:
  33. Return Value:
  34. --*/
  35. {
  36. PATALK_NODE pNode;
  37. ATALK_ERROR error = ATALK_NO_ERROR;
  38. ATALK_NODEADDR desiredNode = { UNKNOWN_NETWORK, UNKNOWN_NODE};
  39. PWSTR NodeName;
  40. KIRQL OldIrql;
  41. ACQUIRE_SPIN_LOCK(&pPortDesc->pd_Lock, &OldIrql);
  42. do
  43. {
  44. if ((pPortDesc->pd_Flags & PD_FINDING_NODE) == 0)
  45. {
  46. pPortDesc->pd_Flags |= PD_FINDING_NODE;
  47. }
  48. else
  49. {
  50. // Return if we are already trying to find a node
  51. error = ATALK_NODE_FINDING;
  52. break;
  53. }
  54. // We should not be here if we have already allocated a router node and the user nodes
  55. ASSERT(!RouterNode || ((pPortDesc->pd_Flags & PD_ROUTER_NODE) == 0));
  56. ASSERT ((pPortDesc->pd_Flags & (PD_ROUTER_NODE | PD_USER_NODE_1 | PD_USER_NODE_2))
  57. != (PD_ROUTER_NODE | PD_USER_NODE_1 | PD_USER_NODE_2));
  58. // On non-extended ports we only allow one node! The theory being that some
  59. // LocalTalk cards are too smart for their own good and have a concept of
  60. // their "source node number" and thus only support one node, also on
  61. // non-extended ports, nodes are scarse.
  62. if (!EXT_NET(pPortDesc))
  63. {
  64. // For a localtalk node we do things differently.
  65. // During initialization time, we would have obtained
  66. // the address from the mac, that will be the node
  67. // address.
  68. ASSERT(pPortDesc->pd_Flags & PD_BOUND);
  69. ASSERT(pPortDesc->pd_AlapNode != 0);
  70. // This needs to be initialized to UNKNOWN_NETWORK or obtained
  71. // from the net during initialization.
  72. ASSERT(pPortDesc->pd_NetworkRange.anr_FirstNetwork == UNKNOWN_NETWORK);
  73. if (!ATALK_SUCCESS((error = AtalkInitNodeAllocate(pPortDesc, &pNode))))
  74. {
  75. LOG_ERRORONPORT(pPortDesc,
  76. EVENT_ATALK_INIT_COULDNOTGETNODE,
  77. 0,
  78. NULL,
  79. 0);
  80. break;
  81. }
  82. // Use the allocated structure to set the info.
  83. // Thread this into the port structure.
  84. pPortDesc->pd_LtNetwork =
  85. pNode->an_NodeAddr.atn_Network =
  86. pPortDesc->pd_NetworkRange.anr_FirstNetwork;
  87. pNode->an_NodeAddr.atn_Node = (BYTE)pPortDesc->pd_AlapNode;
  88. // Reference the port for this node.
  89. AtalkPortReferenceByPtrNonInterlock(pPortDesc, &error);
  90. if (!ATALK_SUCCESS(error))
  91. {
  92. AtalkFreeMemory(pNode);
  93. break;
  94. }
  95. // Now put it in the port descriptor
  96. pNode->an_Next = pPortDesc->pd_Nodes;
  97. pPortDesc->pd_Nodes = pNode;
  98. }
  99. else
  100. {
  101. // Use PRAM values if we have them
  102. if (RouterNode)
  103. {
  104. NodeName = ROUTER_NODE_VALUE;
  105. if (pPortDesc->pd_RoutersPramNode.atn_Network != UNKNOWN_NETWORK)
  106. {
  107. desiredNode = pPortDesc->pd_RoutersPramNode;
  108. }
  109. }
  110. else
  111. {
  112. if ((pPortDesc->pd_Flags & PD_USER_NODE_1) == 0)
  113. {
  114. NodeName = USER_NODE1_VALUE;
  115. if (pPortDesc->pd_UsersPramNode1.atn_Network != UNKNOWN_NETWORK)
  116. {
  117. // If we are not a router node, and the first user node
  118. // has not been allocated...
  119. desiredNode = pPortDesc->pd_UsersPramNode1;
  120. }
  121. }
  122. else if ((pPortDesc->pd_Flags & PD_USER_NODE_2) == 0)
  123. {
  124. NodeName = USER_NODE2_VALUE;
  125. if (pPortDesc->pd_UsersPramNode2.atn_Network != UNKNOWN_NETWORK)
  126. {
  127. // If we are not a router node, and the second user node
  128. // has not been allocated...
  129. desiredNode = pPortDesc->pd_UsersPramNode2;
  130. }
  131. }
  132. }
  133. // Flags should be set so future get node requests return failure
  134. // until we are done with this attempt. We need to call
  135. // the aarp routines without the lock held - they will
  136. // block.
  137. ASSERT(pPortDesc->pd_Flags & PD_FINDING_NODE);
  138. RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql);
  139. // If this routine succeeds in finding the node, it
  140. // will chain in the atalkNode into the port. It also
  141. // returns with the proper flags set/reset in the
  142. // pPortDesc structure. It will also have referenced the port
  143. // and inserted the node into the port's node list.
  144. error = AtalkInitAarpForNodeOnPort(pPortDesc,
  145. AllowStartupRange,
  146. desiredNode,
  147. &pNode);
  148. ACQUIRE_SPIN_LOCK(&pPortDesc->pd_Lock, &OldIrql);
  149. if (!ATALK_SUCCESS(error))
  150. {
  151. // AARP for node failed.
  152. LOG_ERRORONPORT(pPortDesc,
  153. EVENT_ATALK_INIT_COULDNOTGETNODE,
  154. 0,
  155. NULL,
  156. 0);
  157. }
  158. }
  159. } while (FALSE);
  160. // Ok, done finding node. No need for a crit section.
  161. pPortDesc->pd_Flags &= ~PD_FINDING_NODE;
  162. if (ATALK_SUCCESS(error))
  163. {
  164. // If router node, remember it in port descriptor
  165. // Do this before setting up the rtmp/nbp listeners.
  166. // In anycase, clients must check this value for null,
  167. // not guaranteed as zip socket could already be open.
  168. if (RouterNode)
  169. pPortDesc->pd_RouterNode = pNode;
  170. RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql);
  171. // Setup the RTMP, NBP and EP listeners on this node.
  172. // These will be the non-router versions. StartRouting
  173. // calls will then switch them to be the router versions
  174. // at the appropriate time.
  175. error = AtalkInitDdpOpenStaticSockets(pPortDesc, pNode);
  176. if (ATALK_SUCCESS(error))
  177. {
  178. if (EXT_NET(pPortDesc))
  179. {
  180. // We always save this address.
  181. AtalkInitNodeSavePramAddr(pPortDesc,
  182. NodeName,
  183. &pNode->an_NodeAddr);
  184. }
  185. // Return the address of the node opened.
  186. if (NodeAddr != NULL)
  187. *NodeAddr = pNode->an_NodeAddr;
  188. }
  189. else
  190. {
  191. // Error opening sockets. Release node, return failure
  192. LOG_ERRORONPORT(pPortDesc,
  193. EVENT_ATALK_NODE_OPENSOCKETS,
  194. 0,
  195. NULL,
  196. 0);
  197. AtalkNodeReleaseOnPort(pPortDesc, pNode);
  198. }
  199. }
  200. else
  201. {
  202. RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql);
  203. }
  204. if (!ATALK_SUCCESS(error))
  205. {
  206. DBGPRINT(DBG_COMP_NODE, DBG_LEVEL_INFO,
  207. ("Creation node on port %lx failed! %lx\n",
  208. pPortDesc, error));
  209. }
  210. else
  211. {
  212. DBGPRINT(DBG_COMP_NODE, DBG_LEVEL_INFO,
  213. ("Creation node on port %lx with addr %lx.%lx and p%lx\n",
  214. pPortDesc, pNode->an_NodeAddr.atn_Network,
  215. pNode->an_NodeAddr.atn_Node, pNode));
  216. }
  217. return(error);
  218. }
  219. ATALK_ERROR
  220. AtalkNodeReleaseOnPort(
  221. PPORT_DESCRIPTOR pPortDesc,
  222. PATALK_NODE pNode
  223. )
  224. /*++
  225. Routine Description:
  226. Arguments:
  227. Return Value:
  228. --*/
  229. {
  230. PDDP_ADDROBJ pDdpAddr, pNextAddr;
  231. ATALK_ERROR error;
  232. KIRQL OldIrql;
  233. SHORT i;
  234. DBGPRINT(DBG_COMP_NODE, DBG_LEVEL_WARN,
  235. ("AtalkNodeReleaseOnPort: Releasing node %lx on port %lx!\n", pNode, pPortDesc));
  236. ACQUIRE_SPIN_LOCK(&pNode->an_Lock, &OldIrql);
  237. if ((pNode->an_NodeAddr.atn_Network == AtalkUserNode1.atn_Network) &&
  238. (pNode->an_NodeAddr.atn_Node == AtalkUserNode1.atn_Node))
  239. {
  240. pPortDesc->pd_Flags &= ~PD_USER_NODE_1;
  241. AtalkUserNode1.atn_Network = 0;
  242. AtalkUserNode1.atn_Node = 0;
  243. }
  244. else if ((pNode->an_NodeAddr.atn_Network == AtalkUserNode2.atn_Network) &&
  245. (pNode->an_NodeAddr.atn_Node == AtalkUserNode2.atn_Node))
  246. {
  247. pPortDesc->pd_Flags &= ~PD_USER_NODE_2;
  248. AtalkUserNode2.atn_Network = 0;
  249. AtalkUserNode2.atn_Node = 0;
  250. }
  251. if ((pNode->an_Flags & AN_CLOSING) == 0)
  252. {
  253. // Set the closing flag.
  254. pNode->an_Flags |= AN_CLOSING;
  255. // First close all the sockets on the node
  256. for (i = 0; i < NODE_DDPAO_HASH_SIZE; i++)
  257. {
  258. pNextAddr = NULL;
  259. AtalkDdpReferenceNextNc(pNode->an_DdpAoHash[i],
  260. &pDdpAddr,
  261. &error);
  262. if (!ATALK_SUCCESS(error))
  263. {
  264. // Check the other hash table entries. No non-closing
  265. // sockets on this list.
  266. continue;
  267. }
  268. while (TRUE)
  269. {
  270. // Get the next non-closing node using our referenced node before
  271. // closing it. Note we use pDdpAddr->...Flink.
  272. AtalkDdpReferenceNextNc(pDdpAddr->ddpao_Next,
  273. &pNextAddr,
  274. &error);
  275. // Close the referenced ddp addr after releasing the node lock.
  276. RELEASE_SPIN_LOCK(&pNode->an_Lock, OldIrql);
  277. if (pDdpAddr->ddpao_Flags & DDPAO_SOCK_INTERNAL)
  278. {
  279. AtalkDdpCloseAddress(pDdpAddr, NULL, NULL);
  280. }
  281. else
  282. {
  283. AtalkDdpPnPSuspendAddress(pDdpAddr);
  284. }
  285. // Dereference the address.
  286. AtalkDdpDereference(pDdpAddr);
  287. ACQUIRE_SPIN_LOCK(&pNode->an_Lock, &OldIrql);
  288. if (pNextAddr != NULL)
  289. pDdpAddr = pNextAddr;
  290. else
  291. break;
  292. }
  293. }
  294. RELEASE_SPIN_LOCK(&pNode->an_Lock, OldIrql);
  295. // Remove the creation reference for this node.
  296. AtalkNodeDereference(pNode);
  297. }
  298. else
  299. {
  300. // We are already closing.
  301. RELEASE_SPIN_LOCK(&pNode->an_Lock, OldIrql);
  302. }
  303. return(ATALK_NO_ERROR);
  304. }
  305. BOOLEAN
  306. AtalkNodeExistsOnPort(
  307. PPORT_DESCRIPTOR pPortDesc,
  308. PATALK_NODEADDR pNodeAddr
  309. )
  310. /*++
  311. Routine Description:
  312. Arguments:
  313. Return Value:
  314. --*/
  315. {
  316. PATALK_NODE pCheckNode;
  317. BOOLEAN exists = FALSE;
  318. ACQUIRE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
  319. for (pCheckNode = pPortDesc->pd_Nodes;
  320. pCheckNode != NULL;
  321. pCheckNode = pCheckNode->an_Next)
  322. {
  323. if (ATALK_NODES_EQUAL(&pCheckNode->an_NodeAddr, pNodeAddr))
  324. {
  325. exists = TRUE;
  326. break;
  327. }
  328. }
  329. RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
  330. return(exists);
  331. }
  332. VOID
  333. AtalkInitNodeSavePramAddr(
  334. IN PPORT_DESCRIPTOR pPortDesc,
  335. IN PWSTR RegValue,
  336. OUT PATALK_NODEADDR pNode
  337. )
  338. /*++
  339. Routine Description:
  340. Arguments:
  341. Return Value:
  342. --*/
  343. {
  344. UNICODE_STRING valueName;
  345. ULONG bytesWritten;
  346. ULONG ValueToSave;
  347. // Save the node value as xxxx00yy where xxxx is network, yy is node
  348. ValueToSave = (pNode->atn_Network << 16) + pNode->atn_Node;
  349. RtlInitUnicodeString (&valueName, RegValue);
  350. ZwSetValueKey(pPortDesc->pd_AdapterInfoHandle,
  351. &valueName,
  352. 0,
  353. REG_DWORD,
  354. &ValueToSave,
  355. sizeof(ULONG));
  356. }
  357. VOID
  358. AtalkInitNodeGetPramAddr(
  359. IN PPORT_DESCRIPTOR pPortDesc,
  360. IN PWSTR RegValue,
  361. OUT PATALK_NODEADDR pNode
  362. )
  363. /*++
  364. Routine Description:
  365. Arguments:
  366. Return Value:
  367. --*/
  368. {
  369. NTSTATUS Status;
  370. UNICODE_STRING valueName;
  371. ULONG bytesWritten;
  372. ULONG ValueRead;
  373. BYTE buffer[sizeof(KEY_VALUE_FULL_INFORMATION) + 32];
  374. PKEY_VALUE_FULL_INFORMATION nodeValue = (PKEY_VALUE_FULL_INFORMATION)buffer;
  375. RtlInitUnicodeString (&valueName, RegValue);
  376. Status = ZwQueryValueKey(pPortDesc->pd_AdapterInfoHandle,
  377. &valueName,
  378. KeyValueFullInformation,
  379. buffer,
  380. sizeof(buffer),
  381. &bytesWritten);
  382. if (NT_SUCCESS(Status))
  383. {
  384. ValueRead = *(PULONG)(buffer + nodeValue->DataOffset);
  385. }
  386. else
  387. {
  388. ValueRead = 0;
  389. ASSERT (UNKNOWN_NETWORK == 0);
  390. ASSERT (UNKNOWN_NODE == 0);
  391. }
  392. pNode->atn_Node = (BYTE)(ValueRead & 0xFF);
  393. pNode->atn_Network = (USHORT)(ValueRead >> 16);
  394. if ((pNode->atn_Network == UNKNOWN_NETWORK) ||
  395. (pNode->atn_Node == UNKNOWN_NODE))
  396. {
  397. pNode->atn_Node = UNKNOWN_NODE;
  398. pNode->atn_Network = UNKNOWN_NETWORK;
  399. }
  400. }
  401. VOID
  402. AtalkZapPramValue(
  403. IN PPORT_DESCRIPTOR pPortDesc,
  404. IN PWSTR RegValue
  405. )
  406. {
  407. UNICODE_STRING valueName;
  408. ULONG bytesWritten;
  409. ULONG ValueToSave;
  410. // Write 0 to the value to zap it for now.
  411. ValueToSave = 0;
  412. RtlInitUnicodeString (&valueName, RegValue);
  413. ZwSetValueKey(pPortDesc->pd_AdapterInfoHandle,
  414. &valueName,
  415. 0,
  416. REG_DWORD,
  417. &ValueToSave,
  418. sizeof(ULONG));
  419. }
  420. ATALK_ERROR
  421. AtalkInitNodeAllocate(
  422. IN PPORT_DESCRIPTOR pPortDesc,
  423. OUT PATALK_NODE *ppNode
  424. )
  425. /*++
  426. Routine Description:
  427. Arguments:
  428. Return Value:
  429. --*/
  430. {
  431. PATALK_NODE pNode;
  432. // Allocate a new active Node structure
  433. if ((pNode = (PATALK_NODE)AtalkAllocZeroedMemory(sizeof(ATALK_NODE))) == NULL)
  434. {
  435. return(ATALK_RESR_MEM);
  436. }
  437. // Initialize some elements of the structure. Remaining stuff
  438. // done when the node is actually being inserted into the port
  439. // hash table.
  440. #if DBG
  441. pNode->an_Signature = AN_SIGNATURE;
  442. #endif
  443. // Initialize the Nbp Id & Enumerator
  444. pNode->an_NextNbpId = 0;
  445. pNode->an_NextNbpEnum = 0;
  446. pNode->an_NextDynSkt = FIRST_DYNAMIC_SOCKET;
  447. INITIALIZE_SPIN_LOCK(&pNode->an_Lock);
  448. pNode->an_Port = pPortDesc; // Port on which node exists
  449. pNode->an_RefCount = 1; // Reference for creation.
  450. // Return pointer to allocated node
  451. *ppNode = pNode;
  452. return(ATALK_NO_ERROR);
  453. }
  454. VOID
  455. AtalkNodeRefByAddr(
  456. IN PPORT_DESCRIPTOR pPortDesc,
  457. IN PATALK_NODEADDR NodeAddr,
  458. OUT PATALK_NODE * ppNode,
  459. OUT PATALK_ERROR pErr
  460. )
  461. /*++
  462. Routine Description:
  463. Arguments:
  464. Return Value:
  465. --*/
  466. {
  467. PATALK_NODE pNode;
  468. KIRQL OldIrql;
  469. BOOLEAN foundNode = FALSE;
  470. *pErr = ATALK_NODE_NONEXISTENT;
  471. ACQUIRE_SPIN_LOCK(&pPortDesc->pd_Lock, &OldIrql);
  472. for (pNode = pPortDesc->pd_Nodes; pNode != NULL; pNode = pNode->an_Next)
  473. {
  474. ASSERT(VALID_ATALK_NODE(pNode));
  475. // Note: On non-extended ports, there should be only one pNode.
  476. if (((NodeAddr->atn_Network == CABLEWIDE_BROADCAST_NETWORK) ||
  477. (pNode->an_NodeAddr.atn_Network == NodeAddr->atn_Network) ||
  478. (!EXT_NET(pPortDesc) && (pNode->an_NodeAddr.atn_Network == UNKNOWN_NETWORK)))
  479. &&
  480. ((NodeAddr->atn_Node == ATALK_BROADCAST_NODE) ||
  481. (pNode->an_NodeAddr.atn_Node == NodeAddr->atn_Node)))
  482. {
  483. DBGPRINT(DBG_COMP_NODE, DBG_LEVEL_INFO,
  484. ("AtalkNodeRefByAddr: Found: %lx.%lx for Lookup: %lx.%lx\n",
  485. pNode->an_NodeAddr.atn_Network, pNode->an_NodeAddr.atn_Node,
  486. NodeAddr->atn_Network, NodeAddr->atn_Node));
  487. foundNode = TRUE;
  488. break;
  489. }
  490. }
  491. if (foundNode)
  492. {
  493. AtalkNodeRefByPtr(pNode, pErr);
  494. // Return a pointer to the referenced node.
  495. if (ATALK_SUCCESS(*pErr))
  496. {
  497. ASSERT(ppNode != NULL);
  498. ASSERT(pNode != NULL);
  499. *ppNode = pNode;
  500. }
  501. }
  502. RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql);
  503. }
  504. VOID
  505. AtalkNodeRefNextNc(
  506. IN PATALK_NODE pNode,
  507. IN PATALK_NODE * ppNode,
  508. OUT PATALK_ERROR pErr
  509. )
  510. /*++
  511. Routine Description:
  512. MUST BE CALLED WITH THE PORTLOCK HELD!
  513. Arguments:
  514. Return Value:
  515. --*/
  516. {
  517. *pErr = ATALK_FAILURE;
  518. *ppNode = NULL;
  519. for (; pNode != NULL; pNode = pNode->an_Next)
  520. {
  521. ASSERT(VALID_ATALK_NODE(pNode));
  522. AtalkNodeRefByPtr(pNode, pErr);
  523. if (ATALK_SUCCESS(*pErr))
  524. {
  525. // Ok, this node is referenced!
  526. *ppNode = pNode;
  527. break;
  528. }
  529. }
  530. }
  531. VOID
  532. AtalkNodeDeref(
  533. IN OUT PATALK_NODE pNode
  534. )
  535. /*++
  536. Routine Description:
  537. Arguments:
  538. Return Value:
  539. --*/
  540. {
  541. PPORT_DESCRIPTOR pPortDesc = pNode->an_Port;
  542. KIRQL OldIrql;
  543. BOOLEAN done = FALSE;
  544. ASSERT(VALID_ATALK_NODE(pNode));
  545. ACQUIRE_SPIN_LOCK(&pNode->an_Lock, &OldIrql);
  546. ASSERT(pNode->an_RefCount > 0);
  547. if (--pNode->an_RefCount == 0)
  548. {
  549. done = TRUE;
  550. }
  551. RELEASE_SPIN_LOCK(&pNode->an_Lock, OldIrql);
  552. if (done)
  553. {
  554. PATALK_NODE *ppNode;
  555. ASSERT((pNode->an_Flags & AN_CLOSING) != 0);
  556. DBGPRINT(DBG_COMP_NODE, DBG_LEVEL_WARN,
  557. ("AtalkNodeDeref: Freeing node %lx\n", pNode));
  558. ACQUIRE_SPIN_LOCK(&pPortDesc->pd_Lock, &OldIrql);
  559. // Remove this guy from the port linkage
  560. for (ppNode = &pNode->an_Port->pd_Nodes;
  561. *ppNode != NULL;
  562. ppNode = &((*ppNode)->an_Next))
  563. {
  564. if (*ppNode == pNode)
  565. {
  566. *ppNode = pNode->an_Next;
  567. break;
  568. }
  569. }
  570. RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql);
  571. // Dereference the port for this node
  572. AtalkPortDereference(pPortDesc);
  573. // Free the node structure
  574. AtalkFreeMemory(pNode);
  575. }
  576. }
  577.