Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

429 lines
11 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. cxaddr.c
  5. Abstract:
  6. TDI Address Object management code.
  7. Author:
  8. Mike Massa (mikemas) February 20, 1997
  9. Revision History:
  10. Who When What
  11. -------- -------- ----------------------------------------------
  12. mikemas 02-20-97 created
  13. Notes:
  14. --*/
  15. #include "precomp.h"
  16. #pragma hdrstop
  17. #include "cxaddr.tmh"
  18. #define CX_WILDCARD_PORT 0 // 0 means assign a port.
  19. #define CX_MIN_USER_PORT 1025 // Minimum value for a wildcard port
  20. #define CX_MAX_USER_PORT 5000 // Maximim value for a user port.
  21. #define CX_NUM_USER_PORTS (CX_MAX_USER_PORT - CX_MIN_USER_PORT + 1)
  22. //
  23. // Address Object Data
  24. //
  25. USHORT CxNextUserPort = CX_MIN_USER_PORT;
  26. LIST_ENTRY CxAddrObjTable[CX_ADDROBJ_TABLE_SIZE];
  27. #if DBG
  28. CN_LOCK CxAddrObjTableLock = {0,0};
  29. #else // DBG
  30. CN_LOCK CxAddrObjTableLock = 0;
  31. #endif // DBG
  32. NTSTATUS
  33. CxParseTransportAddress(
  34. IN TRANSPORT_ADDRESS UNALIGNED *AddrList,
  35. IN ULONG AddressListLength,
  36. OUT CL_NODE_ID * Node,
  37. OUT PUSHORT Port
  38. )
  39. {
  40. LONG i;
  41. PTA_ADDRESS currentAddr;
  42. TDI_ADDRESS_CLUSTER UNALIGNED * validAddr;
  43. if (AddressListLength >= sizeof(TA_CLUSTER_ADDRESS)) {
  44. //
  45. // Find an address we can use.
  46. //
  47. currentAddr = (PTA_ADDRESS) AddrList->Address;
  48. for (i = 0; i < AddrList->TAAddressCount; i++) {
  49. if ( (currentAddr->AddressType == TDI_ADDRESS_TYPE_CLUSTER) &&
  50. (currentAddr->AddressLength >= TDI_ADDRESS_LENGTH_CLUSTER)
  51. )
  52. {
  53. validAddr = (TDI_ADDRESS_CLUSTER UNALIGNED *)
  54. currentAddr->Address;
  55. *Node = validAddr->Node;
  56. *Port = validAddr->Port;
  57. return(STATUS_SUCCESS);
  58. }
  59. else {
  60. if ( AddressListLength >=
  61. (currentAddr->AddressLength + sizeof(TA_CLUSTER_ADDRESS))
  62. )
  63. {
  64. AddressListLength -= currentAddr->AddressLength;
  65. currentAddr = (PTA_ADDRESS)
  66. ( currentAddr->Address +
  67. currentAddr->AddressLength
  68. );
  69. }
  70. else {
  71. break;
  72. }
  73. }
  74. }
  75. }
  76. return(STATUS_INVALID_ADDRESS_COMPONENT);
  77. } // CxParseTransportAddress
  78. PCX_ADDROBJ
  79. CxFindAddressObject(
  80. IN USHORT Port
  81. )
  82. /*++
  83. Notes:
  84. Called with AO Table lock held.
  85. Returns with address object lock held.
  86. --*/
  87. {
  88. PLIST_ENTRY entry;
  89. ULONG hashBucket = CX_ADDROBJ_TABLE_HASH(Port);
  90. PCX_ADDROBJ addrObj;
  91. for ( entry = CxAddrObjTable[hashBucket].Flink;
  92. entry != &(CxAddrObjTable[hashBucket]);
  93. entry = entry->Flink
  94. )
  95. {
  96. addrObj = CONTAINING_RECORD(
  97. entry,
  98. CX_ADDROBJ,
  99. AOTableLinkage
  100. );
  101. if (addrObj->LocalPort == Port) {
  102. CnAcquireLockAtDpc(&(addrObj->Lock));
  103. addrObj->Irql = DISPATCH_LEVEL;
  104. return(addrObj);
  105. }
  106. }
  107. return(NULL);
  108. } // CxFindAddressObject
  109. NTSTATUS
  110. CxOpenAddress(
  111. OUT PCN_FSCONTEXT * CnFsContext,
  112. IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress,
  113. IN ULONG TransportAddressLength
  114. )
  115. {
  116. PCX_ADDROBJ addrObj, oldAddrObj;
  117. NTSTATUS status;
  118. CL_NODE_ID nodeId;
  119. USHORT port;
  120. CN_IRQL tableIrql;
  121. ULONG i;
  122. ULONG hashBucket;
  123. status = CxParseTransportAddress(
  124. TransportAddress,
  125. TransportAddressLength,
  126. &nodeId,
  127. &port
  128. );
  129. if (status != STATUS_SUCCESS) {
  130. IF_CNDBG(CN_DEBUG_ADDROBJ) {
  131. CNPRINT((
  132. "[Clusnet] Open address - failed to parse address, status %lx\n",
  133. status
  134. ));
  135. }
  136. return(status);
  137. }
  138. addrObj = CnAllocatePool(sizeof(CX_ADDROBJ));
  139. if (addrObj == NULL) {
  140. return(STATUS_INSUFFICIENT_RESOURCES);
  141. }
  142. RtlZeroMemory(addrObj, sizeof(CX_ADDROBJ));
  143. CN_INIT_SIGNATURE(&(addrObj->FsContext), CX_ADDROBJ_SIG);
  144. CnInitializeLock(&(addrObj->Lock), CX_ADDROBJ_LOCK);
  145. addrObj->Flags |= CX_AO_FLAG_CHECKSTATE;
  146. CnAcquireLock(&CxAddrObjTableLock, &tableIrql);
  147. // If no port is specified we have to assign one. If there is a
  148. // port specified, we need to make sure that the port isn't
  149. // already open. If the input address is a wildcard, we need to
  150. // assign one ourselves.
  151. if (port == CX_WILDCARD_PORT) {
  152. port = CxNextUserPort;
  153. for (i = 0; i < CX_NUM_USER_PORTS; i++, port++) {
  154. if (port > CX_MAX_USER_PORT) {
  155. port = CX_MIN_USER_PORT;
  156. }
  157. oldAddrObj = CxFindAddressObject(port);
  158. if (oldAddrObj == NULL) {
  159. IF_CNDBG(CN_DEBUG_ADDROBJ) {
  160. CNPRINT(("[Clusnet] Assigning port %u\n", port));
  161. }
  162. break; // Found an unused port.
  163. }
  164. CnReleaseLockFromDpc(&(oldAddrObj->Lock));
  165. }
  166. if (i == CX_NUM_USER_PORTS) { // Couldn't find a free port.
  167. IF_CNDBG(CN_DEBUG_ADDROBJ) {
  168. CNPRINT((
  169. "[Clusnet] No free wildcard ports.\n"
  170. ));
  171. }
  172. CnReleaseLock(&CxAddrObjTableLock, tableIrql);
  173. CnFreePool(addrObj);
  174. return (STATUS_TOO_MANY_ADDRESSES);
  175. }
  176. CxNextUserPort = port + 1;
  177. } else { // Address was specificed
  178. oldAddrObj = CxFindAddressObject(port);
  179. if (oldAddrObj != NULL) {
  180. IF_CNDBG(CN_DEBUG_ADDROBJ) {
  181. CNPRINT((
  182. "[Clusnet] Port %u is already in use.\n",
  183. port
  184. ));
  185. }
  186. CnReleaseLockFromDpc(&(oldAddrObj->Lock));
  187. CnReleaseLock(&CxAddrObjTableLock, tableIrql);
  188. CnFreePool(addrObj);
  189. return (STATUS_ADDRESS_ALREADY_EXISTS);
  190. }
  191. }
  192. addrObj->LocalPort = port;
  193. hashBucket = CX_ADDROBJ_TABLE_HASH(port);
  194. InsertHeadList(
  195. &(CxAddrObjTable[hashBucket]),
  196. &(addrObj->AOTableLinkage)
  197. );
  198. *CnFsContext = (PCN_FSCONTEXT) addrObj;
  199. IF_CNDBG(CN_DEBUG_ADDROBJ) {
  200. CNPRINT((
  201. "[Clusnet] Opened address object %p for port %u\n",
  202. addrObj,
  203. port
  204. ));
  205. }
  206. CnTrace(
  207. CDP_ADDR_DETAIL, CdpTraceOpenAO,
  208. "[Clusnet] Opened address object %p for port %u.",
  209. addrObj,
  210. port
  211. );
  212. CnReleaseLock(&CxAddrObjTableLock, tableIrql);
  213. return(STATUS_SUCCESS);
  214. } // CxOpenAddress
  215. NTSTATUS
  216. CxCloseAddress(
  217. IN PCN_FSCONTEXT CnFsContext
  218. )
  219. {
  220. PCX_ADDROBJ addrObj = (PCX_ADDROBJ) CnFsContext;
  221. CN_IRQL tableIrql;
  222. IF_CNDBG(CN_DEBUG_ADDROBJ) {
  223. CNPRINT((
  224. "[Clusnet] Closed address object %p for port %u\n",
  225. addrObj,
  226. addrObj->LocalPort
  227. ));
  228. }
  229. CnTrace(
  230. CDP_ADDR_DETAIL, CdpTraceCloseAO,
  231. "[Clusnet] Closed address object %p for port %u.",
  232. addrObj,
  233. addrObj->LocalPort
  234. );
  235. CnAcquireLock(&CxAddrObjTableLock, &tableIrql);
  236. CnAcquireLockAtDpc(&(addrObj->Lock));
  237. RemoveEntryList(&(addrObj->AOTableLinkage));
  238. CnReleaseLockFromDpc(&(addrObj->Lock));
  239. CnReleaseLock(&CxAddrObjTableLock, tableIrql);
  240. //
  241. // The address object memory will be freed by the common code.
  242. //
  243. return(STATUS_SUCCESS);
  244. } // CxCloseAddress
  245. NTSTATUS
  246. CxSetEventHandler(
  247. IN PIRP Irp,
  248. IN PIO_STACK_LOCATION IrpSp
  249. )
  250. {
  251. NTSTATUS status = STATUS_SUCCESS;
  252. PTDI_REQUEST_KERNEL_SET_EVENT request;
  253. PCX_ADDROBJ addrObj;
  254. CN_IRQL irql;
  255. //
  256. // Since this ioctl registers a callback function pointer, ensure
  257. // that it was issued by a kernel-mode component.
  258. //
  259. if (Irp->RequestorMode != KernelMode) {
  260. return(STATUS_ACCESS_DENIED);
  261. }
  262. addrObj = (PCX_ADDROBJ) IrpSp->FileObject->FsContext;
  263. request = (PTDI_REQUEST_KERNEL_SET_EVENT) &(IrpSp->Parameters);
  264. IF_CNDBG(CN_DEBUG_ADDROBJ) {
  265. CNPRINT((
  266. "[Clusnet] TdiSetEvent type %u handler %p context %p\n",
  267. request->EventType,
  268. request->EventHandler,
  269. request->EventContext
  270. ));
  271. }
  272. CnAcquireLock(&(addrObj->Lock), &irql);
  273. switch (request->EventType) {
  274. case TDI_EVENT_ERROR:
  275. addrObj->ErrorHandler = request->EventHandler;
  276. addrObj->ErrorContext = request->EventContext;
  277. break;
  278. case TDI_EVENT_RECEIVE_DATAGRAM:
  279. addrObj->ReceiveDatagramHandler = request->EventHandler;
  280. addrObj->ReceiveDatagramContext = request->EventContext;
  281. break;
  282. case TDI_EVENT_CHAINED_RECEIVE_DATAGRAM:
  283. addrObj->ChainedReceiveDatagramHandler = request->EventHandler;
  284. addrObj->ChainedReceiveDatagramContext = request->EventContext;
  285. break;
  286. default:
  287. status = STATUS_INVALID_PARAMETER;
  288. break;
  289. }
  290. CnReleaseLock(&(addrObj->Lock), irql);
  291. Irp->IoStatus.Status = status;
  292. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  293. return(status);
  294. } // CxSetEventHandler
  295. VOID
  296. CxBuildTdiAddress(
  297. PVOID Buffer,
  298. CL_NODE_ID Node,
  299. USHORT Port,
  300. BOOLEAN Verified
  301. )
  302. /*++
  303. Routine Description:
  304. Called when we need to build a TDI address structure. We fill in
  305. the specifed buffer with the correct information in the correct
  306. format.
  307. Arguments:
  308. Buffer - Buffer to be filled in as TDI address structure.
  309. Node - Node ID to fill in.
  310. Port - Port to be filled in.
  311. Verified - During a receive, whether clusnet verified the
  312. signature and data
  313. Return Value:
  314. Nothing
  315. --*/
  316. {
  317. PTRANSPORT_ADDRESS xportAddr;
  318. PTA_ADDRESS taAddr;
  319. xportAddr = (PTRANSPORT_ADDRESS) Buffer;
  320. xportAddr->TAAddressCount = 1;
  321. taAddr = xportAddr->Address;
  322. taAddr->AddressType = TDI_ADDRESS_TYPE_CLUSTER;
  323. taAddr->AddressLength = sizeof(TDI_ADDRESS_CLUSTER);
  324. ((PTDI_ADDRESS_CLUSTER) taAddr->Address)->Port = Port;
  325. ((PTDI_ADDRESS_CLUSTER) taAddr->Address)->Node = Node;
  326. ((PTDI_ADDRESS_CLUSTER) taAddr->Address)->ReservedMBZ =
  327. ((Verified) ? 1 : 0);
  328. }