Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenfileobjs.c
Go to the documentation of this file.
00001 /* 00002 * COPYRIGHT: See COPYING in the top level directory 00003 * PROJECT: ReactOS TCP/IP protocol driver 00004 * FILE: tcpip/fileobjs.c 00005 * PURPOSE: Routines for handling file objects 00006 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) 00007 * REVISIONS: 00008 * CSH 01/08-2000 Created 00009 */ 00010 00011 #include "precomp.h" 00012 00013 00014 /* List of all address file objects managed by this driver */ 00015 LIST_ENTRY AddressFileListHead; 00016 KSPIN_LOCK AddressFileListLock; 00017 00018 /* List of all connection endpoint file objects managed by this driver */ 00019 LIST_ENTRY ConnectionEndpointListHead; 00020 KSPIN_LOCK ConnectionEndpointListLock; 00021 00022 /* 00023 * FUNCTION: Searches through address file entries to find the first match 00024 * ARGUMENTS: 00025 * Address = IP address 00026 * Port = Port number 00027 * Protocol = Protocol number 00028 * SearchContext = Pointer to search context 00029 * RETURNS: 00030 * Pointer to address file, NULL if none was found 00031 */ 00032 PADDRESS_FILE AddrSearchFirst( 00033 PIP_ADDRESS Address, 00034 USHORT Port, 00035 USHORT Protocol, 00036 PAF_SEARCH SearchContext) 00037 { 00038 KIRQL OldIrql; 00039 00040 SearchContext->Address = Address; 00041 SearchContext->Port = Port; 00042 SearchContext->Protocol = Protocol; 00043 00044 TcpipAcquireSpinLock(&AddressFileListLock, &OldIrql); 00045 00046 SearchContext->Next = AddressFileListHead.Flink; 00047 00048 if (!IsListEmpty(&AddressFileListHead)) 00049 ReferenceObject(CONTAINING_RECORD(SearchContext->Next, ADDRESS_FILE, ListEntry)); 00050 00051 TcpipReleaseSpinLock(&AddressFileListLock, OldIrql); 00052 00053 return AddrSearchNext(SearchContext); 00054 } 00055 00056 BOOLEAN AddrIsBroadcastMatch( 00057 PIP_ADDRESS UnicastAddress, 00058 PIP_ADDRESS BroadcastAddress ) { 00059 IF_LIST_ITER(IF); 00060 00061 ForEachInterface(IF) { 00062 if ((AddrIsUnspecified(UnicastAddress) || 00063 AddrIsEqual(&IF->Unicast, UnicastAddress)) && 00064 (AddrIsEqual(&IF->Broadcast, BroadcastAddress))) 00065 return TRUE; 00066 } EndFor(IF); 00067 00068 return FALSE; 00069 } 00070 00071 BOOLEAN AddrReceiveMatch( 00072 PIP_ADDRESS LocalAddress, 00073 PIP_ADDRESS RemoteAddress) 00074 { 00075 if (AddrIsEqual(LocalAddress, RemoteAddress)) 00076 { 00077 /* Unicast address match */ 00078 return TRUE; 00079 } 00080 00081 if (AddrIsBroadcastMatch(LocalAddress, RemoteAddress)) 00082 { 00083 /* Broadcast address match */ 00084 return TRUE; 00085 } 00086 00087 if (AddrIsUnspecified(LocalAddress)) 00088 { 00089 /* Local address unspecified */ 00090 return TRUE; 00091 } 00092 00093 if (AddrIsUnspecified(RemoteAddress)) 00094 { 00095 /* Remote address unspecified */ 00096 return TRUE; 00097 } 00098 00099 return FALSE; 00100 } 00101 00102 /* 00103 * FUNCTION: Searches through address file entries to find next match 00104 * ARGUMENTS: 00105 * SearchContext = Pointer to search context 00106 * RETURNS: 00107 * Pointer to address file, NULL if none was found 00108 */ 00109 PADDRESS_FILE AddrSearchNext( 00110 PAF_SEARCH SearchContext) 00111 { 00112 PLIST_ENTRY CurrentEntry; 00113 PIP_ADDRESS IPAddress; 00114 KIRQL OldIrql; 00115 PADDRESS_FILE Current = NULL; 00116 BOOLEAN Found = FALSE; 00117 00118 TcpipAcquireSpinLock(&AddressFileListLock, &OldIrql); 00119 00120 if (SearchContext->Next == &AddressFileListHead) 00121 { 00122 TcpipReleaseSpinLock(&AddressFileListLock, OldIrql); 00123 return NULL; 00124 } 00125 00126 /* Remove the extra reference we added to keep this address file in memory */ 00127 DereferenceObject(CONTAINING_RECORD(SearchContext->Next, ADDRESS_FILE, ListEntry)); 00128 00129 CurrentEntry = SearchContext->Next; 00130 00131 while (CurrentEntry != &AddressFileListHead) { 00132 Current = CONTAINING_RECORD(CurrentEntry, ADDRESS_FILE, ListEntry); 00133 00134 IPAddress = &Current->Address; 00135 00136 TI_DbgPrint(DEBUG_ADDRFILE, ("Comparing: ((%d, %d, %s), (%d, %d, %s)).\n", 00137 WN2H(Current->Port), 00138 Current->Protocol, 00139 A2S(IPAddress), 00140 WN2H(SearchContext->Port), 00141 SearchContext->Protocol, 00142 A2S(SearchContext->Address))); 00143 00144 /* See if this address matches the search criteria */ 00145 if ((Current->Port == SearchContext->Port) && 00146 (Current->Protocol == SearchContext->Protocol) && 00147 (AddrReceiveMatch(IPAddress, SearchContext->Address))) { 00148 /* We've found a match */ 00149 Found = TRUE; 00150 break; 00151 } 00152 CurrentEntry = CurrentEntry->Flink; 00153 } 00154 00155 if (Found) 00156 { 00157 SearchContext->Next = CurrentEntry->Flink; 00158 00159 if (SearchContext->Next != &AddressFileListHead) 00160 { 00161 /* Reference the next address file to prevent the link from disappearing behind our back */ 00162 ReferenceObject(CONTAINING_RECORD(SearchContext->Next, ADDRESS_FILE, ListEntry)); 00163 } 00164 } 00165 else 00166 Current = NULL; 00167 00168 TcpipReleaseSpinLock(&AddressFileListLock, OldIrql); 00169 00170 return Current; 00171 } 00172 00173 VOID AddrFileFree( 00174 PVOID Object) 00175 /* 00176 * FUNCTION: Frees an address file object 00177 * ARGUMENTS: 00178 * Object = Pointer to address file object to free 00179 */ 00180 { 00181 PADDRESS_FILE AddrFile = Object; 00182 KIRQL OldIrql; 00183 PDATAGRAM_RECEIVE_REQUEST ReceiveRequest; 00184 PDATAGRAM_SEND_REQUEST SendRequest; 00185 PLIST_ENTRY CurrentEntry; 00186 00187 TI_DbgPrint(MID_TRACE, ("Called.\n")); 00188 00189 /* We should not be associated with a connection here */ 00190 ASSERT(!AddrFile->Connection); 00191 00192 /* Remove address file from the global list */ 00193 TcpipAcquireSpinLock(&AddressFileListLock, &OldIrql); 00194 RemoveEntryList(&AddrFile->ListEntry); 00195 TcpipReleaseSpinLock(&AddressFileListLock, OldIrql); 00196 00197 /* FIXME: Kill TCP connections on this address file object */ 00198 00199 /* Return pending requests with error */ 00200 00201 TI_DbgPrint(DEBUG_ADDRFILE, ("Aborting receive requests on AddrFile at (0x%X).\n", AddrFile)); 00202 00203 /* Go through pending receive request list and cancel them all */ 00204 while ((CurrentEntry = ExInterlockedRemoveHeadList(&AddrFile->ReceiveQueue, &AddrFile->Lock))) { 00205 ReceiveRequest = CONTAINING_RECORD(CurrentEntry, DATAGRAM_RECEIVE_REQUEST, ListEntry); 00206 (*ReceiveRequest->Complete)(ReceiveRequest->Context, STATUS_CANCELLED, 0); 00207 /* ExFreePoolWithTag(ReceiveRequest, DATAGRAM_RECV_TAG); FIXME: WTF? */ 00208 } 00209 00210 TI_DbgPrint(DEBUG_ADDRFILE, ("Aborting send requests on address file at (0x%X).\n", AddrFile)); 00211 00212 /* Go through pending send request list and cancel them all */ 00213 while ((CurrentEntry = ExInterlockedRemoveHeadList(&AddrFile->ReceiveQueue, &AddrFile->Lock))) { 00214 SendRequest = CONTAINING_RECORD(CurrentEntry, DATAGRAM_SEND_REQUEST, ListEntry); 00215 (*SendRequest->Complete)(SendRequest->Context, STATUS_CANCELLED, 0); 00216 ExFreePoolWithTag(SendRequest, DATAGRAM_SEND_TAG); 00217 } 00218 00219 /* Protocol specific handling */ 00220 switch (AddrFile->Protocol) { 00221 case IPPROTO_TCP: 00222 if (AddrFile->Port) 00223 { 00224 TCPFreePort(AddrFile->Port); 00225 } 00226 break; 00227 00228 case IPPROTO_UDP: 00229 UDPFreePort( AddrFile->Port ); 00230 break; 00231 } 00232 00233 RemoveEntityByContext(AddrFile); 00234 00235 ExFreePoolWithTag(Object, ADDR_FILE_TAG); 00236 } 00237 00238 00239 VOID ControlChannelFree( 00240 PVOID Object) 00241 /* 00242 * FUNCTION: Frees an address file object 00243 * ARGUMENTS: 00244 * Object = Pointer to address file object to free 00245 */ 00246 { 00247 ExFreePoolWithTag(Object, CONTROL_CHANNEL_TAG); 00248 } 00249 00250 00251 /* 00252 * FUNCTION: Open an address file object 00253 * ARGUMENTS: 00254 * Request = Pointer to TDI request structure for this request 00255 * Address = Pointer to address to be opened 00256 * Protocol = Protocol on which to open the address 00257 * Options = Pointer to option buffer 00258 * RETURNS: 00259 * Status of operation 00260 */ 00261 NTSTATUS FileOpenAddress( 00262 PTDI_REQUEST Request, 00263 PTA_IP_ADDRESS Address, 00264 USHORT Protocol, 00265 PVOID Options) 00266 { 00267 PADDRESS_FILE AddrFile; 00268 00269 TI_DbgPrint(MID_TRACE, ("Called (Proto %d).\n", Protocol)); 00270 00271 AddrFile = ExAllocatePoolWithTag(NonPagedPool, sizeof(ADDRESS_FILE), 00272 ADDR_FILE_TAG); 00273 if (!AddrFile) { 00274 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); 00275 return STATUS_INSUFFICIENT_RESOURCES; 00276 } 00277 00278 RtlZeroMemory(AddrFile, sizeof(ADDRESS_FILE)); 00279 00280 AddrFile->RefCount = 1; 00281 AddrFile->Free = AddrFileFree; 00282 00283 /* Set our default options */ 00284 AddrFile->TTL = 128; 00285 AddrFile->DF = 0; 00286 AddrFile->BCast = 1; 00287 AddrFile->HeaderIncl = 1; 00288 00289 /* Make sure address is a local unicast address or 0 */ 00290 /* FIXME: IPv4 only */ 00291 AddrFile->Family = Address->Address[0].AddressType; 00292 AddrFile->Address.Address.IPv4Address = Address->Address[0].Address[0].in_addr; 00293 AddrFile->Address.Type = IP_ADDRESS_V4; 00294 00295 if (!AddrIsUnspecified(&AddrFile->Address) && 00296 !AddrLocateInterface(&AddrFile->Address)) { 00297 ExFreePoolWithTag(AddrFile, ADDR_FILE_TAG); 00298 TI_DbgPrint(MIN_TRACE, ("Non-local address given (0x%X).\n", A2S(&AddrFile->Address))); 00299 return STATUS_INVALID_ADDRESS; 00300 } 00301 00302 TI_DbgPrint(MID_TRACE, ("Opening address %s for communication (P=%d U=%d).\n", 00303 A2S(&AddrFile->Address), Protocol, IPPROTO_UDP)); 00304 00305 /* Protocol specific handling */ 00306 switch (Protocol) { 00307 case IPPROTO_TCP: 00308 if (Address->Address[0].Address[0].sin_port) 00309 { 00310 /* The client specified an explicit port so we force a bind to this */ 00311 AddrFile->Port = TCPAllocatePort(Address->Address[0].Address[0].sin_port); 00312 00313 /* Check for bind success */ 00314 if (AddrFile->Port == 0xffff) 00315 { 00316 ExFreePoolWithTag(AddrFile, ADDR_FILE_TAG); 00317 return STATUS_ADDRESS_ALREADY_EXISTS; 00318 } 00319 00320 /* Sanity check */ 00321 ASSERT(Address->Address[0].Address[0].sin_port == AddrFile->Port); 00322 } 00323 else if (!AddrIsUnspecified(&AddrFile->Address)) 00324 { 00325 /* The client is trying to bind to a local address so allocate a port now too */ 00326 AddrFile->Port = TCPAllocatePort(0); 00327 00328 /* Check for bind success */ 00329 if (AddrFile->Port == 0xffff) 00330 { 00331 ExFreePoolWithTag(AddrFile, ADDR_FILE_TAG); 00332 return STATUS_ADDRESS_ALREADY_EXISTS; 00333 } 00334 } 00335 else 00336 { 00337 /* The client wants an unspecified port with an unspecified address so we wait to see what the TCP library gives us */ 00338 AddrFile->Port = 0; 00339 } 00340 00341 AddEntity(CO_TL_ENTITY, AddrFile, CO_TL_TCP); 00342 00343 AddrFile->Send = NULL; /* TCPSendData */ 00344 break; 00345 00346 case IPPROTO_UDP: 00347 TI_DbgPrint(MID_TRACE,("Allocating udp port\n")); 00348 AddrFile->Port = 00349 UDPAllocatePort(Address->Address[0].Address[0].sin_port); 00350 00351 if ((Address->Address[0].Address[0].sin_port && 00352 AddrFile->Port != Address->Address[0].Address[0].sin_port) || 00353 AddrFile->Port == 0xffff) 00354 { 00355 ExFreePoolWithTag(AddrFile, ADDR_FILE_TAG); 00356 return STATUS_ADDRESS_ALREADY_EXISTS; 00357 } 00358 00359 TI_DbgPrint(MID_TRACE,("Setting port %d (wanted %d)\n", 00360 AddrFile->Port, 00361 Address->Address[0].Address[0].sin_port)); 00362 00363 AddEntity(CL_TL_ENTITY, AddrFile, CL_TL_UDP); 00364 00365 AddrFile->Send = UDPSendDatagram; 00366 break; 00367 00368 case IPPROTO_ICMP: 00369 AddrFile->Port = 0; 00370 AddrFile->Send = ICMPSendDatagram; 00371 00372 /* FIXME: Verify this */ 00373 AddEntity(ER_ENTITY, AddrFile, ER_ICMP); 00374 break; 00375 00376 default: 00377 /* Use raw IP for all other protocols */ 00378 AddrFile->Port = 0; 00379 AddrFile->Send = RawIPSendDatagram; 00380 00381 /* FIXME: Verify this */ 00382 AddEntity(CL_TL_ENTITY, AddrFile, 0); 00383 break; 00384 } 00385 00386 TI_DbgPrint(MID_TRACE, ("IP protocol number for address file object is %d.\n", 00387 Protocol)); 00388 00389 TI_DbgPrint(MID_TRACE, ("Port number for address file object is %d.\n", 00390 WN2H(AddrFile->Port))); 00391 00392 /* Set protocol */ 00393 AddrFile->Protocol = Protocol; 00394 00395 /* Initialize receive and transmit queues */ 00396 InitializeListHead(&AddrFile->ReceiveQueue); 00397 InitializeListHead(&AddrFile->TransmitQueue); 00398 00399 /* Initialize spin lock that protects the address file object */ 00400 KeInitializeSpinLock(&AddrFile->Lock); 00401 00402 /* Return address file object */ 00403 Request->Handle.AddressHandle = AddrFile; 00404 00405 /* Add address file to global list */ 00406 ExInterlockedInsertTailList( 00407 &AddressFileListHead, 00408 &AddrFile->ListEntry, 00409 &AddressFileListLock); 00410 00411 TI_DbgPrint(MAX_TRACE, ("Leaving.\n")); 00412 00413 return STATUS_SUCCESS; 00414 } 00415 00416 00417 /* 00418 * FUNCTION: Closes an address file object 00419 * ARGUMENTS: 00420 * Request = Pointer to TDI request structure for this request 00421 * RETURNS: 00422 * Status of operation 00423 */ 00424 NTSTATUS FileCloseAddress( 00425 PTDI_REQUEST Request) 00426 { 00427 PADDRESS_FILE AddrFile = Request->Handle.AddressHandle; 00428 KIRQL OldIrql; 00429 00430 if (!Request->Handle.AddressHandle) return STATUS_INVALID_PARAMETER; 00431 00432 LockObject(AddrFile, &OldIrql); 00433 00434 /* We have to close this listener because we started it */ 00435 if( AddrFile->Listener ) 00436 { 00437 TCPClose( AddrFile->Listener ); 00438 } 00439 00440 UnlockObject(AddrFile, OldIrql); 00441 00442 DereferenceObject(AddrFile); 00443 00444 TI_DbgPrint(MAX_TRACE, ("Leaving.\n")); 00445 00446 return STATUS_SUCCESS; 00447 } 00448 00449 00450 /* 00451 * FUNCTION: Opens a connection file object 00452 * ARGUMENTS: 00453 * Request = Pointer to TDI request structure for this request 00454 * ClientContext = Pointer to client context information 00455 * RETURNS: 00456 * Status of operation 00457 */ 00458 NTSTATUS FileOpenConnection( 00459 PTDI_REQUEST Request, 00460 PVOID ClientContext) 00461 { 00462 NTSTATUS Status; 00463 PCONNECTION_ENDPOINT Connection; 00464 00465 TI_DbgPrint(MID_TRACE, ("Called.\n")); 00466 00467 Connection = TCPAllocateConnectionEndpoint( ClientContext ); 00468 00469 if( !Connection ) return STATUS_NO_MEMORY; 00470 00471 Status = TCPSocket( Connection, AF_INET, SOCK_STREAM, IPPROTO_TCP ); 00472 00473 if( !NT_SUCCESS(Status) ) { 00474 DereferenceObject( Connection ); 00475 return Status; 00476 } 00477 00478 /* Return connection endpoint file object */ 00479 Request->Handle.ConnectionContext = Connection; 00480 00481 TI_DbgPrint(MAX_TRACE, ("Leaving.\n")); 00482 00483 return STATUS_SUCCESS; 00484 } 00485 00486 /* 00487 * FUNCTION: Closes an connection file object 00488 * ARGUMENTS: 00489 * Request = Pointer to TDI request structure for this request 00490 * RETURNS: 00491 * Status of operation 00492 */ 00493 NTSTATUS FileCloseConnection( 00494 PTDI_REQUEST Request) 00495 { 00496 PCONNECTION_ENDPOINT Connection; 00497 00498 TI_DbgPrint(MID_TRACE, ("Called.\n")); 00499 00500 Connection = Request->Handle.ConnectionContext; 00501 00502 if (!Connection) return STATUS_INVALID_PARAMETER; 00503 00504 TCPClose( Connection ); 00505 00506 Request->Handle.ConnectionContext = NULL; 00507 00508 TI_DbgPrint(MAX_TRACE, ("Leaving.\n")); 00509 00510 return STATUS_SUCCESS; 00511 } 00512 00513 /* 00514 * FUNCTION: Opens a control channel file object 00515 * ARGUMENTS: 00516 * Request = Pointer to TDI request structure for this request 00517 * RETURNS: 00518 * Status of operation 00519 */ 00520 NTSTATUS FileOpenControlChannel( 00521 PTDI_REQUEST Request) 00522 { 00523 PCONTROL_CHANNEL ControlChannel; 00524 TI_DbgPrint(MID_TRACE, ("Called.\n")); 00525 00526 ControlChannel = ExAllocatePoolWithTag(NonPagedPool, sizeof(*ControlChannel), 00527 CONTROL_CHANNEL_TAG); 00528 00529 if (!ControlChannel) { 00530 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); 00531 return STATUS_INSUFFICIENT_RESOURCES; 00532 } 00533 00534 RtlZeroMemory(ControlChannel, sizeof(CONTROL_CHANNEL)); 00535 00536 /* Make sure address is a local unicast address or 0 */ 00537 00538 /* Locate address entry. If specified address is 0, a random address is chosen */ 00539 00540 /* Initialize receive and transmit queues */ 00541 InitializeListHead(&ControlChannel->ListEntry); 00542 00543 /* Initialize spin lock that protects the address file object */ 00544 KeInitializeSpinLock(&ControlChannel->Lock); 00545 00546 ControlChannel->RefCount = 1; 00547 ControlChannel->Free = ControlChannelFree; 00548 00549 /* Return address file object */ 00550 Request->Handle.ControlChannel = ControlChannel; 00551 00552 TI_DbgPrint(MAX_TRACE, ("Leaving.\n")); 00553 00554 return STATUS_SUCCESS; 00555 } 00556 00557 /* 00558 * FUNCTION: Closes a control channel file object 00559 * ARGUMENTS: 00560 * Request = Pointer to TDI request structure for this request 00561 * RETURNS: 00562 * Status of operation 00563 */ 00564 NTSTATUS FileCloseControlChannel( 00565 PTDI_REQUEST Request) 00566 { 00567 if (!Request->Handle.ControlChannel) return STATUS_INVALID_PARAMETER; 00568 00569 DereferenceObject((PCONTROL_CHANNEL)Request->Handle.ControlChannel); 00570 00571 Request->Handle.ControlChannel = NULL; 00572 00573 return STATUS_SUCCESS; 00574 } 00575 00576 /* EOF */ Generated on Fri May 25 2012 04:26:14 for ReactOS by
1.7.6.1
|