1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS TCP/IP protocol driver 4 * FILE: transport/udp/udp.c 5 * PURPOSE: User Datagram Protocol routines 6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) 7 * REVISIONS: 8 * CSH 01/08-2000 Created 9 */ 10 11 #include "precomp.h" 12 13 BOOLEAN UDPInitialized = FALSE; 14 PORT_SET UDPPorts; 15 16 NTSTATUS AddUDPHeaderIPv4( 17 PADDRESS_FILE AddrFile, 18 PIP_ADDRESS RemoteAddress, 19 USHORT RemotePort, 20 PIP_ADDRESS LocalAddress, 21 USHORT LocalPort, 22 PIP_PACKET IPPacket, 23 PVOID Data, 24 UINT DataLength) 25 /* 26 * FUNCTION: Adds an IPv4 and UDP header to an IP packet 27 * ARGUMENTS: 28 * SendRequest = Pointer to send request 29 * LocalAddress = Pointer to our local address 30 * LocalPort = The port we send this datagram from 31 * IPPacket = Pointer to IP packet 32 * RETURNS: 33 * Status of operation 34 */ 35 { 36 PUDP_HEADER UDPHeader; 37 NTSTATUS Status; 38 39 TI_DbgPrint(MID_TRACE, ("Packet: %x NdisPacket %x\n", 40 IPPacket, IPPacket->NdisPacket)); 41 42 Status = AddGenericHeaderIPv4 43 ( AddrFile, RemoteAddress, RemotePort, 44 LocalAddress, LocalPort, 45 IPPacket, DataLength, IPPROTO_UDP, 46 sizeof(UDP_HEADER), (PVOID *)&UDPHeader ); 47 48 if (!NT_SUCCESS(Status)) 49 return Status; 50 51 /* Port values are already big-endian values */ 52 UDPHeader->SourcePort = LocalPort; 53 UDPHeader->DestPort = RemotePort; 54 UDPHeader->Checksum = 0; 55 /* Length of UDP header and data */ 56 UDPHeader->Length = WH2N(DataLength + sizeof(UDP_HEADER)); 57 58 TI_DbgPrint(MID_TRACE, ("Copying data (hdr %x data %x (%d))\n", 59 IPPacket->Header, IPPacket->Data, 60 (PCHAR)IPPacket->Data - (PCHAR)IPPacket->Header)); 61 62 RtlCopyMemory(IPPacket->Data, Data, DataLength); 63 64 UDPHeader->Checksum = UDPv4ChecksumCalculate((PIPv4_HEADER)IPPacket->Header, 65 (PUCHAR)UDPHeader, 66 DataLength + sizeof(UDP_HEADER)); 67 UDPHeader->Checksum = WH2N(UDPHeader->Checksum); 68 69 TI_DbgPrint(MID_TRACE, ("Packet: %d ip %d udp %d payload\n", 70 (PCHAR)UDPHeader - (PCHAR)IPPacket->Header, 71 (PCHAR)IPPacket->Data - (PCHAR)UDPHeader, 72 DataLength)); 73 74 return STATUS_SUCCESS; 75 } 76 77 78 NTSTATUS BuildUDPPacket( 79 PADDRESS_FILE AddrFile, 80 PIP_PACKET Packet, 81 PIP_ADDRESS RemoteAddress, 82 USHORT RemotePort, 83 PIP_ADDRESS LocalAddress, 84 USHORT LocalPort, 85 PCHAR DataBuffer, 86 UINT DataLen ) 87 /* 88 * FUNCTION: Builds an UDP packet 89 * ARGUMENTS: 90 * Context = Pointer to context information (DATAGRAM_SEND_REQUEST) 91 * LocalAddress = Pointer to our local address 92 * LocalPort = The port we send this datagram from 93 * IPPacket = Address of pointer to IP packet 94 * RETURNS: 95 * Status of operation 96 */ 97 { 98 NTSTATUS Status; 99 100 TI_DbgPrint(MAX_TRACE, ("Called.\n")); 101 102 /* FIXME: Assumes IPv4 */ 103 IPInitializePacket(Packet, IP_ADDRESS_V4); 104 105 Packet->TotalSize = sizeof(IPv4_HEADER) + sizeof(UDP_HEADER) + DataLen; 106 107 /* Prepare packet */ 108 Status = AllocatePacketWithBuffer(&Packet->NdisPacket, 109 NULL, 110 Packet->TotalSize ); 111 112 if( !NT_SUCCESS(Status) ) 113 { 114 Packet->Free(Packet); 115 return Status; 116 } 117 118 TI_DbgPrint(MID_TRACE, ("Allocated packet: %x\n", Packet->NdisPacket)); 119 TI_DbgPrint(MID_TRACE, ("Local Addr : %s\n", A2S(LocalAddress))); 120 TI_DbgPrint(MID_TRACE, ("Remote Addr: %s\n", A2S(RemoteAddress))); 121 122 switch (RemoteAddress->Type) { 123 case IP_ADDRESS_V4: 124 Status = AddUDPHeaderIPv4(AddrFile, RemoteAddress, RemotePort, 125 LocalAddress, LocalPort, Packet, DataBuffer, DataLen); 126 break; 127 case IP_ADDRESS_V6: 128 /* FIXME: Support IPv6 */ 129 TI_DbgPrint(MIN_TRACE, ("IPv6 UDP datagrams are not supported.\n")); 130 default: 131 Status = STATUS_UNSUCCESSFUL; 132 break; 133 } 134 if (!NT_SUCCESS(Status)) { 135 TI_DbgPrint(MIN_TRACE, ("Cannot add UDP header. Status = (0x%X)\n", 136 Status)); 137 Packet->Free(Packet); 138 return Status; 139 } 140 141 TI_DbgPrint(MID_TRACE, ("Displaying packet\n")); 142 143 DISPLAY_IP_PACKET(Packet); 144 145 TI_DbgPrint(MID_TRACE, ("Leaving\n")); 146 147 return STATUS_SUCCESS; 148 } 149 150 NTSTATUS UDPSendDatagram( 151 PADDRESS_FILE AddrFile, 152 PTDI_CONNECTION_INFORMATION ConnInfo, 153 PCHAR BufferData, 154 ULONG DataSize, 155 PULONG DataUsed ) 156 /* 157 * FUNCTION: Sends an UDP datagram to a remote address 158 * ARGUMENTS: 159 * Request = Pointer to TDI request 160 * ConnInfo = Pointer to connection information 161 * Buffer = Pointer to NDIS buffer with data 162 * DataSize = Size in bytes of data to be sent 163 * RETURNS: 164 * Status of operation 165 */ 166 { 167 IP_PACKET Packet; 168 PTA_IP_ADDRESS RemoteAddressTa = (PTA_IP_ADDRESS)ConnInfo->RemoteAddress; 169 IP_ADDRESS RemoteAddress; 170 IP_ADDRESS LocalAddress; 171 USHORT RemotePort; 172 NTSTATUS Status; 173 PNEIGHBOR_CACHE_ENTRY NCE; 174 175 LockObject(AddrFile); 176 177 TI_DbgPrint(MID_TRACE,("Sending Datagram(%x %x %x %d)\n", 178 AddrFile, ConnInfo, BufferData, DataSize)); 179 TI_DbgPrint(MID_TRACE,("RemoteAddressTa: %x\n", RemoteAddressTa)); 180 181 switch( RemoteAddressTa->Address[0].AddressType ) { 182 case TDI_ADDRESS_TYPE_IP: 183 RemoteAddress.Type = IP_ADDRESS_V4; 184 RemoteAddress.Address.IPv4Address = 185 RemoteAddressTa->Address[0].Address[0].in_addr; 186 RemotePort = RemoteAddressTa->Address[0].Address[0].sin_port; 187 break; 188 189 default: 190 UnlockObject(AddrFile); 191 return STATUS_UNSUCCESSFUL; 192 } 193 194 LocalAddress = AddrFile->Address; 195 if (AddrIsUnspecified(&LocalAddress)) 196 { 197 /* If the local address is unspecified (0), 198 * then use the unicast address of the 199 * interface we're sending over 200 */ 201 if(!(NCE = RouteGetRouteToDestination( &RemoteAddress ))) { 202 UnlockObject(AddrFile); 203 return STATUS_NETWORK_UNREACHABLE; 204 } 205 206 LocalAddress = NCE->Interface->Unicast; 207 } 208 else 209 { 210 if(!(NCE = NBLocateNeighbor( &LocalAddress, NULL ))) { 211 UnlockObject(AddrFile); 212 return STATUS_INVALID_PARAMETER; 213 } 214 } 215 216 Status = BuildUDPPacket( AddrFile, 217 &Packet, 218 &RemoteAddress, 219 RemotePort, 220 &LocalAddress, 221 AddrFile->Port, 222 BufferData, 223 DataSize ); 224 225 UnlockObject(AddrFile); 226 227 if( !NT_SUCCESS(Status) ) 228 return Status; 229 230 Status = IPSendDatagram(&Packet, NCE); 231 if (!NT_SUCCESS(Status)) 232 return Status; 233 234 *DataUsed = DataSize; 235 236 return STATUS_SUCCESS; 237 } 238 239 240 VOID UDPReceive(PIP_INTERFACE Interface, PIP_PACKET IPPacket) 241 /* 242 * FUNCTION: Receives and queues a UDP datagram 243 * ARGUMENTS: 244 * NTE = Pointer to net table entry which the packet was received on 245 * IPPacket = Pointer to an IP packet that was received 246 * NOTES: 247 * This is the low level interface for receiving UDP datagrams. It strips 248 * the UDP header from a packet and delivers the data to anyone that wants it 249 */ 250 { 251 AF_SEARCH SearchContext; 252 PIPv4_HEADER IPv4Header; 253 PADDRESS_FILE AddrFile; 254 PUDP_HEADER UDPHeader; 255 PIP_ADDRESS DstAddress, SrcAddress; 256 UINT DataSize, i; 257 258 TI_DbgPrint(MAX_TRACE, ("Called.\n")); 259 260 switch (IPPacket->Type) { 261 /* IPv4 packet */ 262 case IP_ADDRESS_V4: 263 IPv4Header = IPPacket->Header; 264 DstAddress = &IPPacket->DstAddr; 265 SrcAddress = &IPPacket->SrcAddr; 266 break; 267 268 /* IPv6 packet */ 269 case IP_ADDRESS_V6: 270 TI_DbgPrint(MIN_TRACE, ("Discarded IPv6 UDP datagram (%i bytes).\n", IPPacket->TotalSize)); 271 272 /* FIXME: IPv6 is not supported */ 273 return; 274 275 default: 276 return; 277 } 278 279 UDPHeader = (PUDP_HEADER)IPPacket->Data; 280 281 /* Calculate and validate UDP checksum */ 282 i = UDPv4ChecksumCalculate(IPv4Header, 283 (PUCHAR)UDPHeader, 284 WH2N(UDPHeader->Length)); 285 if (i != DH2N(0x0000FFFF) && UDPHeader->Checksum != 0) 286 { 287 TI_DbgPrint(MIN_TRACE, ("Bad checksum on packet received.\n")); 288 return; 289 } 290 291 /* Sanity checks */ 292 i = WH2N(UDPHeader->Length); 293 if ((i < sizeof(UDP_HEADER)) || (i > IPPacket->TotalSize - IPPacket->Position)) { 294 /* Incorrect or damaged packet received, discard it */ 295 TI_DbgPrint(MIN_TRACE, ("Incorrect or damaged UDP packet received.\n")); 296 return; 297 } 298 299 DataSize = i - sizeof(UDP_HEADER); 300 301 /* Go to UDP data area */ 302 IPPacket->Data = (PVOID)((ULONG_PTR)IPPacket->Data + sizeof(UDP_HEADER)); 303 304 /* Locate a receive request on destination address file object 305 and deliver the packet if one is found. If there is no receive 306 request on the address file object, call the associated receive 307 handler. If no receive handler is registered, drop the packet */ 308 309 AddrFile = AddrSearchFirst(DstAddress, 310 UDPHeader->DestPort, 311 IPPROTO_UDP, 312 &SearchContext); 313 if (AddrFile) { 314 do { 315 DGDeliverData(AddrFile, 316 SrcAddress, 317 DstAddress, 318 UDPHeader->SourcePort, 319 UDPHeader->DestPort, 320 IPPacket, 321 DataSize); 322 DereferenceObject(AddrFile); 323 } while ((AddrFile = AddrSearchNext(&SearchContext)) != NULL); 324 } else { 325 /* There are no open address files that will take this datagram */ 326 /* FIXME: IPv4 only */ 327 TI_DbgPrint(MID_TRACE, ("Cannot deliver IPv4 UDP datagram to address (0x%X).\n", 328 DN2H(DstAddress->Address.IPv4Address))); 329 330 /* FIXME: Send ICMP reply */ 331 } 332 TI_DbgPrint(MAX_TRACE, ("Leaving.\n")); 333 } 334 335 336 NTSTATUS UDPStartup( 337 VOID) 338 /* 339 * FUNCTION: Initializes the UDP subsystem 340 * RETURNS: 341 * Status of operation 342 */ 343 { 344 NTSTATUS Status; 345 346 RtlZeroMemory(&UDPStats, sizeof(UDP_STATISTICS)); 347 348 Status = PortsStartup( &UDPPorts, 1, UDP_STARTING_PORT + UDP_DYNAMIC_PORTS ); 349 350 if( !NT_SUCCESS(Status) ) return Status; 351 352 /* Register this protocol with IP layer */ 353 IPRegisterProtocol(IPPROTO_UDP, UDPReceive); 354 355 UDPInitialized = TRUE; 356 357 return STATUS_SUCCESS; 358 } 359 360 361 NTSTATUS UDPShutdown( 362 VOID) 363 /* 364 * FUNCTION: Shuts down the UDP subsystem 365 * RETURNS: 366 * Status of operation 367 */ 368 { 369 if (!UDPInitialized) 370 return STATUS_SUCCESS; 371 372 PortsShutdown( &UDPPorts ); 373 374 /* Deregister this protocol with IP layer */ 375 IPRegisterProtocol(IPPROTO_UDP, NULL); 376 377 UDPInitialized = FALSE; 378 379 return STATUS_SUCCESS; 380 } 381 382 UINT UDPAllocatePort( UINT HintPort ) { 383 if( HintPort ) { 384 if( AllocatePort( &UDPPorts, HintPort ) ) return HintPort; 385 else return (UINT)-1; 386 } else return AllocatePortFromRange 387 ( &UDPPorts, UDP_STARTING_PORT, 388 UDP_STARTING_PORT + UDP_DYNAMIC_PORTS ); 389 } 390 391 VOID UDPFreePort( UINT Port ) { 392 DeallocatePort( &UDPPorts, Port ); 393 } 394 395 /* EOF */ 396