]> git.proxmox.com Git - mirror_edk2.git/blob - StdLib/EfiSocketLib/Ip4.c
2d341269cc25c6c0ce1ca583c0566d8854e736e9
[mirror_edk2.git] / StdLib / EfiSocketLib / Ip4.c
1 /** @file
2 Implement the IP4 driver support for the socket layer.
3
4 Copyright (c) 2011, Intel Corporation
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "Socket.h"
16
17
18 /**
19 Get the local socket address
20
21 This routine returns the IPv4 address associated with the local
22 socket.
23
24 This routine is called by ::EslSocketGetLocalAddress to determine the
25 network address for the SOCK_RAW socket.
26
27 @param [in] pPort Address of an ::ESL_PORT structure.
28
29 @param [out] pAddress Network address to receive the local system address
30
31 **/
32 VOID
33 EslIp4LocalAddressGet (
34 IN ESL_PORT * pPort,
35 OUT struct sockaddr * pAddress
36 )
37 {
38 struct sockaddr_in * pLocalAddress;
39 ESL_IP4_CONTEXT * pIp4;
40
41 DBG_ENTER ( );
42
43 //
44 // Return the local address
45 //
46 pIp4 = &pPort->Context.Ip4;
47 pLocalAddress = (struct sockaddr_in *)pAddress;
48 pLocalAddress->sin_family = AF_INET;
49 CopyMem ( &pLocalAddress->sin_addr,
50 &pIp4->ModeData.ConfigData.StationAddress.Addr[0],
51 sizeof ( pLocalAddress->sin_addr ));
52
53 DBG_EXIT ( );
54 }
55
56
57 /**
58 Set the local port address.
59
60 This routine sets the local port address.
61
62 This support routine is called by ::EslSocketPortAllocate.
63
64 @param [in] pPort Address of an ESL_PORT structure
65 @param [in] pSockAddr Address of a sockaddr structure that contains the
66 connection point on the local machine. An IPv4 address
67 of INADDR_ANY specifies that the connection is made to
68 all of the network stacks on the platform. Specifying a
69 specific IPv4 address restricts the connection to the
70 network stack supporting that address. Specifying zero
71 for the port causes the network layer to assign a port
72 number from the dynamic range. Specifying a specific
73 port number causes the network layer to use that port.
74
75 @param [in] bBindTest TRUE = run bind testing
76
77 @retval EFI_SUCCESS The operation was successful
78
79 **/
80 EFI_STATUS
81 EslIp4LocalAddressSet (
82 IN ESL_PORT * pPort,
83 IN CONST struct sockaddr * pSockAddr,
84 IN BOOLEAN bBindTest
85 )
86 {
87 EFI_IP4_CONFIG_DATA * pConfig;
88 CONST struct sockaddr_in * pIpAddress;
89 CONST UINT8 * pIpv4Address;
90 EFI_STATUS Status;
91
92 DBG_ENTER ( );
93
94 //
95 // Validate the address
96 //
97 pIpAddress = (struct sockaddr_in *)pSockAddr;
98 if ( INADDR_BROADCAST == pIpAddress->sin_addr.s_addr ) {
99 //
100 // The local address must not be the broadcast address
101 //
102 Status = EFI_INVALID_PARAMETER;
103 pPort->pSocket->errno = EADDRNOTAVAIL;
104 }
105 else {
106 Status = EFI_SUCCESS;
107
108 //
109 // Set the local address
110 //
111 pIpAddress = (struct sockaddr_in *)pSockAddr;
112 pIpv4Address = (UINT8 *)&pIpAddress->sin_addr.s_addr;
113 pConfig = &pPort->Context.Ip4.ModeData.ConfigData;
114 pConfig->StationAddress.Addr[0] = pIpv4Address[0];
115 pConfig->StationAddress.Addr[1] = pIpv4Address[1];
116 pConfig->StationAddress.Addr[2] = pIpv4Address[2];
117 pConfig->StationAddress.Addr[3] = pIpv4Address[3];
118
119 //
120 // Determine if the default address is used
121 //
122 pConfig->UseDefaultAddress = (BOOLEAN)( 0 == pIpAddress->sin_addr.s_addr );
123
124 //
125 // Display the local address
126 //
127 DEBUG (( DEBUG_BIND,
128 "0x%08x: Port, Local IP4 Address: %d.%d.%d.%d\r\n",
129 pPort,
130 pConfig->StationAddress.Addr[0],
131 pConfig->StationAddress.Addr[1],
132 pConfig->StationAddress.Addr[2],
133 pConfig->StationAddress.Addr[3]));
134
135 //
136 // Set the subnet mask
137 //
138 if ( pConfig->UseDefaultAddress ) {
139 pConfig->SubnetMask.Addr[0] = 0;
140 pConfig->SubnetMask.Addr[1] = 0;
141 pConfig->SubnetMask.Addr[2] = 0;
142 pConfig->SubnetMask.Addr[3] = 0;
143 }
144 else {
145 pConfig->SubnetMask.Addr[0] = 0xff;
146 pConfig->SubnetMask.Addr[1] = 0xff;
147 pConfig->SubnetMask.Addr[2] = 0xff;
148 pConfig->SubnetMask.Addr[3] = 0xff;
149 }
150 }
151
152 //
153 // Return the operation status
154 //
155 DBG_EXIT_STATUS ( Status );
156 return Status;
157 }
158
159
160 /**
161 Get the option value
162
163 This routine handles the IPv4 level options.
164
165 The ::EslSocketOptionGet routine calls this routine to retrieve
166 the IPv4 options one at a time by name.
167
168 @param [in] pSocket Address of an ::ESL_SOCKET structure
169 @param [in] OptionName Name of the option
170 @param [out] ppOptionData Buffer to receive address of option value
171 @param [out] pOptionLength Buffer to receive the option length
172
173 @retval EFI_SUCCESS - Socket data successfully received
174
175 **/
176 EFI_STATUS
177 EslIp4OptionGet (
178 IN ESL_SOCKET * pSocket,
179 IN int OptionName,
180 OUT CONST void ** __restrict ppOptionData,
181 OUT socklen_t * __restrict pOptionLength
182 )
183 {
184 EFI_STATUS Status;
185
186 DBG_ENTER ( );
187
188 //
189 // Assume success
190 //
191 pSocket->errno = 0;
192 Status = EFI_SUCCESS;
193
194 //
195 // Attempt to get the option
196 //
197 switch ( OptionName ) {
198 default:
199 //
200 // Option not supported
201 //
202 pSocket->errno = ENOPROTOOPT;
203 Status = EFI_INVALID_PARAMETER;
204 break;
205
206 case IP_HDRINCL:
207 *ppOptionData = (void *)pSocket->bIncludeHeader;
208 *pOptionLength = sizeof ( pSocket->bIncludeHeader );
209 break;
210 }
211
212 //
213 // Return the operation status
214 //
215 DBG_EXIT_STATUS ( Status );
216 return Status;
217 }
218
219
220 /**
221 Set the option value
222
223 This routine handles the IPv4 level options.
224
225 The ::EslSocketOptionSet routine calls this routine to adjust
226 the IPv4 options one at a time by name.
227
228 @param [in] pSocket Address of an ::ESL_SOCKET structure
229 @param [in] OptionName Name of the option
230 @param [in] pOptionValue Buffer containing the option value
231 @param [in] OptionLength Length of the buffer in bytes
232
233 @retval EFI_SUCCESS - Option successfully set
234
235 **/
236 EFI_STATUS
237 EslIp4OptionSet (
238 IN ESL_SOCKET * pSocket,
239 IN int OptionName,
240 IN CONST void * pOptionValue,
241 IN socklen_t OptionLength
242 )
243 {
244 BOOLEAN bTrueFalse;
245 socklen_t LengthInBytes;
246 UINT8 * pOptionData;
247 EFI_STATUS Status;
248
249 DBG_ENTER ( );
250
251 //
252 // Assume success
253 //
254 pSocket->errno = 0;
255 Status = EFI_SUCCESS;
256
257 //
258 // Determine if the option protocol matches
259 //
260 LengthInBytes = 0;
261 pOptionData = NULL;
262 switch ( OptionName ) {
263 default:
264 //
265 // Protocol level not supported
266 //
267 DEBUG (( DEBUG_INFO | DEBUG_OPTION, "ERROR - Invalid protocol option\r\n" ));
268 pSocket->errno = ENOTSUP;
269 Status = EFI_UNSUPPORTED;
270 break;
271
272 case IP_HDRINCL:
273
274 //
275 // Validate the option length
276 //
277 if ( sizeof ( UINT32 ) == OptionLength ) {
278 //
279 // Restrict the input to TRUE or FALSE
280 //
281 bTrueFalse = TRUE;
282 if ( 0 == *(UINT32 *)pOptionValue ) {
283 bTrueFalse = FALSE;
284 }
285 pOptionValue = &bTrueFalse;
286
287 //
288 // Set the option value
289 //
290 pOptionData = (UINT8 *)&pSocket->bIncludeHeader;
291 LengthInBytes = sizeof ( pSocket->bIncludeHeader );
292 }
293 break;
294 }
295
296 //
297 // Return the operation status
298 //
299 DBG_EXIT_STATUS ( Status );
300 return Status;
301 }
302
303
304 /**
305 Free a receive packet
306
307 This routine performs the network specific operations necessary
308 to free a receive packet.
309
310 This routine is called by ::EslSocketPortCloseTxDone to free a
311 receive packet.
312
313 @param [in] pPacket Address of an ::ESL_PACKET structure.
314 @param [in, out] pRxBytes Address of the count of RX bytes
315
316 **/
317 VOID
318 EslIp4PacketFree (
319 IN ESL_PACKET * pPacket,
320 IN OUT size_t * pRxBytes
321 )
322 {
323 EFI_IP4_RECEIVE_DATA * pRxData;
324 DBG_ENTER ( );
325
326 //
327 // Account for the receive bytes
328 //
329 pRxData = pPacket->Op.Ip4Rx.pRxData;
330 *pRxBytes -= pRxData->HeaderLength + pRxData->DataLength;
331
332 //
333 // Disconnect the buffer from the packet
334 //
335 pPacket->Op.Ip4Rx.pRxData = NULL;
336
337 //
338 // Return the buffer to the IP4 driver
339 //
340 gBS->SignalEvent ( pRxData->RecycleSignal );
341 DBG_EXIT ( );
342 }
343
344
345 /**
346 Initialize the network specific portions of an ::ESL_PORT structure.
347
348 This routine initializes the network specific portions of an
349 ::ESL_PORT structure for use by the socket.
350
351 This support routine is called by ::EslSocketPortAllocate
352 to connect the socket with the underlying network adapter
353 running the IPv4 protocol.
354
355 @param [in] pPort Address of an ESL_PORT structure
356 @param [in] DebugFlags Flags for debug messages
357
358 @retval EFI_SUCCESS - Socket successfully created
359
360 **/
361 EFI_STATUS
362 EslIp4PortAllocate (
363 IN ESL_PORT * pPort,
364 IN UINTN DebugFlags
365 )
366 {
367 EFI_IP4_CONFIG_DATA * pConfig;
368 ESL_SOCKET * pSocket;
369 EFI_STATUS Status;
370
371 DBG_ENTER ( );
372
373 //
374 // Initialize the port
375 //
376 pSocket = pPort->pSocket;
377 pSocket->TxPacketOffset = OFFSET_OF ( ESL_PACKET, Op.Ip4Tx.TxData );
378 pSocket->TxTokenEventOffset = OFFSET_OF ( ESL_IO_MGMT, Token.Ip4Tx.Event );
379 pSocket->TxTokenOffset = OFFSET_OF ( EFI_IP4_COMPLETION_TOKEN, Packet.TxData );
380
381 //
382 // Save the cancel, receive and transmit addresses
383 //
384 pPort->pfnConfigure = (PFN_NET_CONFIGURE)pPort->pProtocol.IPv4->Configure;
385 pPort->pfnRxCancel = (PFN_NET_IO_START)pPort->pProtocol.IPv4->Cancel;
386 pPort->pfnRxStart = (PFN_NET_IO_START)pPort->pProtocol.IPv4->Receive;
387 pPort->pfnTxStart = (PFN_NET_IO_START)pPort->pProtocol.IPv4->Transmit;
388
389 //
390 // Set the configuration flags
391 //
392 pConfig = &pPort->Context.Ip4.ModeData.ConfigData;
393 pConfig->AcceptIcmpErrors = FALSE;
394 pConfig->AcceptBroadcast = FALSE;
395 pConfig->AcceptPromiscuous = FALSE;
396 pConfig->TypeOfService = 0;
397 pConfig->TimeToLive = 255;
398 pConfig->DoNotFragment = FALSE;
399 pConfig->RawData = FALSE;
400 pConfig->ReceiveTimeout = 0;
401 pConfig->TransmitTimeout = 0;
402
403 //
404 // Set the default protocol
405 //
406 pConfig->DefaultProtocol = (UINT8)pSocket->Protocol;
407 pConfig->AcceptAnyProtocol = (BOOLEAN)( 0 == pConfig->DefaultProtocol );
408 Status = EFI_SUCCESS;
409
410 //
411 // Return the operation status
412 //
413 DBG_EXIT_STATUS ( Status );
414 return Status;
415 }
416
417
418 /**
419 Receive data from a network connection.
420
421 This routine attempts to return buffered data to the caller. The
422 data is removed from the urgent queue if the message flag MSG_OOB
423 is specified, otherwise data is removed from the normal queue.
424 See the \ref ReceiveEngine section.
425
426 This routine is called by ::EslSocketReceive to handle the network
427 specific receive operation to support SOCK_RAW sockets.
428
429 @param [in] pPort Address of an ::ESL_PORT structure.
430
431 @param [in] pPacket Address of an ::ESL_PACKET structure.
432
433 @param [in] pbConsumePacket Address of a BOOLEAN indicating if the packet is to be consumed
434
435 @param [in] BufferLength Length of the the buffer
436
437 @param [in] pBuffer Address of a buffer to receive the data.
438
439 @param [in] pDataLength Number of received data bytes in the buffer.
440
441 @param [out] pAddress Network address to receive the remote system address
442
443 @param [out] pSkipBytes Address to receive the number of bytes skipped
444
445 @return Returns the address of the next free byte in the buffer.
446
447 **/
448 UINT8 *
449 EslIp4Receive (
450 IN ESL_PORT * pPort,
451 IN ESL_PACKET * pPacket,
452 IN BOOLEAN * pbConsumePacket,
453 IN size_t BufferLength,
454 IN UINT8 * pBuffer,
455 OUT size_t * pDataLength,
456 OUT struct sockaddr * pAddress,
457 OUT size_t * pSkipBytes
458 )
459 {
460 size_t DataBytes;
461 size_t HeaderBytes;
462 size_t LengthInBytes;
463 struct sockaddr_in * pRemoteAddress;
464 EFI_IP4_RECEIVE_DATA * pRxData;
465
466 DBG_ENTER ( );
467
468 //
469 // Return the remote system address if requested
470 //
471 pRxData = pPacket->Op.Ip4Rx.pRxData;
472 if ( NULL != pAddress ) {
473 //
474 // Build the remote address
475 //
476 DEBUG (( DEBUG_RX,
477 "Getting packet remote address: %d.%d.%d.%d\r\n",
478 pRxData->Header->SourceAddress.Addr[0],
479 pRxData->Header->SourceAddress.Addr[1],
480 pRxData->Header->SourceAddress.Addr[2],
481 pRxData->Header->SourceAddress.Addr[3]));
482 pRemoteAddress = (struct sockaddr_in *)pAddress;
483 CopyMem ( &pRemoteAddress->sin_addr,
484 &pRxData->Header->SourceAddress.Addr[0],
485 sizeof ( pRemoteAddress->sin_addr ));
486 }
487
488 //
489 // Copy the IP header
490 //
491 HeaderBytes = pRxData->HeaderLength;
492 if ( HeaderBytes > BufferLength ) {
493 HeaderBytes = BufferLength;
494 }
495 DEBUG (( DEBUG_RX,
496 "0x%08x --> 0x%08x: Copy header 0x%08x bytes\r\n",
497 pRxData->Header,
498 pBuffer,
499 HeaderBytes ));
500 CopyMem ( pBuffer, pRxData->Header, HeaderBytes );
501 pBuffer += HeaderBytes;
502 LengthInBytes = HeaderBytes;
503
504 //
505 // Copy the received data
506 //
507 if ( 0 < ( BufferLength - LengthInBytes )) {
508 pBuffer = EslSocketCopyFragmentedBuffer ( pRxData->FragmentCount,
509 &pRxData->FragmentTable[0],
510 BufferLength - LengthInBytes,
511 pBuffer,
512 &DataBytes );
513 LengthInBytes += DataBytes;
514 }
515
516 //
517 // Determine if the data is being read
518 //
519 if ( *pbConsumePacket ) {
520 //
521 // Display for the bytes consumed
522 //
523 DEBUG (( DEBUG_RX,
524 "0x%08x: Port account for 0x%08x bytes\r\n",
525 pPort,
526 LengthInBytes ));
527
528 //
529 // Account for any discarded data
530 //
531 *pSkipBytes = pRxData->HeaderLength + pRxData->DataLength - LengthInBytes;
532 }
533
534 //
535 // Return the data length and the buffer address
536 //
537 *pDataLength = LengthInBytes;
538 DBG_EXIT_HEX ( pBuffer );
539 return pBuffer;
540 }
541
542
543 /**
544 Get the remote socket address
545
546 This routine returns the address of the remote connection point
547 associated with the SOCK_RAW socket.
548
549 This routine is called by ::EslSocketGetPeerAddress to detemine
550 the IPv4 address associated with the network adapter.
551
552 @param [in] pPort Address of an ::ESL_PORT structure.
553
554 @param [out] pAddress Network address to receive the remote system address
555
556 **/
557 VOID
558 EslIp4RemoteAddressGet (
559 IN ESL_PORT * pPort,
560 OUT struct sockaddr * pAddress
561 )
562 {
563 struct sockaddr_in * pRemoteAddress;
564 ESL_IP4_CONTEXT * pIp4;
565
566 DBG_ENTER ( );
567
568 //
569 // Return the remote address
570 //
571 pIp4 = &pPort->Context.Ip4;
572 pRemoteAddress = (struct sockaddr_in *)pAddress;
573 pRemoteAddress->sin_family = AF_INET;
574 CopyMem ( &pRemoteAddress->sin_addr,
575 &pIp4->DestinationAddress.Addr[0],
576 sizeof ( pRemoteAddress->sin_addr ));
577
578 DBG_EXIT ( );
579 }
580
581
582 /**
583 Set the remote address
584
585 This routine sets the remote address in the port.
586
587 This routine is called by ::EslSocketConnect to specify the
588 remote network address.
589
590 @param [in] pPort Address of an ::ESL_PORT structure.
591
592 @param [in] pSockAddr Network address of the remote system.
593
594 @param [in] SockAddrLength Length in bytes of the network address.
595
596 @retval EFI_SUCCESS The operation was successful
597
598 **/
599 EFI_STATUS
600 EslIp4RemoteAddressSet (
601 IN ESL_PORT * pPort,
602 IN CONST struct sockaddr * pSockAddr,
603 IN socklen_t SockAddrLength
604 )
605 {
606 ESL_IP4_CONTEXT * pIp4;
607 CONST struct sockaddr_in * pRemoteAddress;
608 EFI_STATUS Status;
609
610 DBG_ENTER ( );
611
612 //
613 // Set the remote address
614 //
615 pIp4 = &pPort->Context.Ip4;
616 pRemoteAddress = (struct sockaddr_in *)pSockAddr;
617 pIp4->DestinationAddress.Addr[0] = (UINT8)( pRemoteAddress->sin_addr.s_addr );
618 pIp4->DestinationAddress.Addr[1] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 8 );
619 pIp4->DestinationAddress.Addr[2] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 16 );
620 pIp4->DestinationAddress.Addr[3] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 24 );
621 Status = EFI_SUCCESS;
622
623 //
624 // Return the operation status
625 //
626 DBG_EXIT_STATUS ( Status );
627 return Status;
628 }
629
630
631 /**
632 Process the receive completion
633
634 This routine keeps the IPv4 driver's buffer and queues it in
635 in FIFO order to the data queue. The IP4 driver's buffer will
636 be returned by either ::EslIp4Receive or ::EslSocketPortCloseTxDone.
637 See the \ref ReceiveEngine section.
638
639 This routine is called by the IPv4 driver when data is
640 received.
641
642 @param [in] Event The receive completion event
643
644 @param [in] pIo The address of an ::ESL_IO_MGMT structure
645
646 **/
647 VOID
648 EslIp4RxComplete (
649 IN EFI_EVENT Event,
650 IN ESL_IO_MGMT * pIo
651 )
652 {
653 size_t LengthInBytes;
654 ESL_PORT * pPort;
655 ESL_PACKET * pPacket;
656 EFI_IP4_RECEIVE_DATA * pRxData;
657 EFI_STATUS Status;
658
659 DBG_ENTER ( );
660
661 //
662 // Get the operation status.
663 //
664 pPort = pIo->pPort;
665 Status = pIo->Token.Ip4Rx.Status;
666
667 //
668 // Get the packet length
669 //
670 pRxData = pIo->Token.Ip4Rx.Packet.RxData;
671 LengthInBytes = pRxData->HeaderLength + pRxData->DataLength;
672
673 //
674 // +--------------------+ +----------------------+
675 // | ESL_IO_MGMT | | Data Buffer |
676 // | | | (Driver owned) |
677 // | +---------------+ +----------------------+
678 // | | Token | ^
679 // | | Rx Event | |
680 // | | | +----------------------+
681 // | | RxData --> | EFI_IP4_RECEIVE_DATA |
682 // +----+---------------+ | (Driver owned) |
683 // +----------------------+
684 // +--------------------+ ^
685 // | ESL_PACKET | .
686 // | | .
687 // | +---------------+ .
688 // | | pRxData --> NULL .......
689 // +----+---------------+
690 //
691 //
692 // Save the data in the packet
693 //
694 pPacket = pIo->pPacket;
695 pPacket->Op.Ip4Rx.pRxData = pRxData;
696
697 //
698 // Complete this request
699 //
700 EslSocketRxComplete ( pIo, Status, LengthInBytes, FALSE );
701 DBG_EXIT ( );
702 }
703
704
705 /**
706 Determine if the socket is configured.
707
708 This routine uses the flag ESL_SOCKET::bConfigured to determine
709 if the network layer's configuration routine has been called.
710 This routine calls the ::EslSocketBind and configuration routines
711 if they were not already called. After the port is configured,
712 the \ref ReceiveEngine is started.
713
714 This routine is called by EslSocketIsConfigured to verify
715 that the socket is configured.
716
717 @param [in] pSocket Address of an ::ESL_SOCKET structure
718
719 @retval EFI_SUCCESS - The port is connected
720 @retval EFI_NOT_STARTED - The port is not connected
721
722 **/
723 EFI_STATUS
724 EslIp4SocketIsConfigured (
725 IN ESL_SOCKET * pSocket
726 )
727 {
728 UINTN Index;
729 ESL_PORT * pPort;
730 ESL_PORT * pNextPort;
731 ESL_IP4_CONTEXT * pIp4;
732 EFI_IP4_PROTOCOL * pIp4Protocol;
733 EFI_STATUS Status;
734 struct sockaddr_in LocalAddress;
735
736 DBG_ENTER ( );
737
738 //
739 // Assume success
740 //
741 Status = EFI_SUCCESS;
742
743 //
744 // Configure the port if necessary
745 //
746 if ( !pSocket->bConfigured ) {
747 //
748 // Fill in the port list if necessary
749 //
750 if ( NULL == pSocket->pPortList ) {
751 LocalAddress.sin_len = sizeof ( LocalAddress );
752 LocalAddress.sin_family = AF_INET;
753 LocalAddress.sin_addr.s_addr = 0;
754 LocalAddress.sin_port = 0;
755 Status = EslSocketBind ( &pSocket->SocketProtocol,
756 (struct sockaddr *)&LocalAddress,
757 LocalAddress.sin_len,
758 &pSocket->errno );
759 }
760
761 //
762 // Walk the port list
763 //
764 pPort = pSocket->pPortList;
765 while ( NULL != pPort ) {
766 //
767 // Update the raw setting
768 //
769 pIp4 = &pPort->Context.Ip4;
770 if ( pSocket->bIncludeHeader ) {
771 //
772 // IP header will be included with the data on transmit
773 //
774 pIp4->ModeData.ConfigData.RawData = TRUE;
775 }
776
777 //
778 // Attempt to configure the port
779 //
780 pNextPort = pPort->pLinkSocket;
781 pIp4Protocol = pPort->pProtocol.IPv4;
782 DEBUG (( DEBUG_TX,
783 "0x%08x: pPort Configuring for %d.%d.%d.%d --> %d.%d.%d.%d\r\n",
784 pPort,
785 pIp4->ModeData.ConfigData.StationAddress.Addr[0],
786 pIp4->ModeData.ConfigData.StationAddress.Addr[1],
787 pIp4->ModeData.ConfigData.StationAddress.Addr[2],
788 pIp4->ModeData.ConfigData.StationAddress.Addr[3],
789 pIp4->DestinationAddress.Addr[0],
790 pIp4->DestinationAddress.Addr[1],
791 pIp4->DestinationAddress.Addr[2],
792 pIp4->DestinationAddress.Addr[3]));
793 Status = pIp4Protocol->Configure ( pIp4Protocol,
794 &pIp4->ModeData.ConfigData );
795 if ( !EFI_ERROR ( Status )) {
796 //
797 // Update the configuration data
798 //
799 Status = pIp4Protocol->GetModeData ( pIp4Protocol,
800 &pIp4->ModeData,
801 NULL,
802 NULL );
803 }
804 if ( EFI_ERROR ( Status )) {
805 DEBUG (( DEBUG_LISTEN,
806 "ERROR - Failed to configure the Ip4 port, Status: %r\r\n",
807 Status ));
808 switch ( Status ) {
809 case EFI_ACCESS_DENIED:
810 pSocket->errno = EACCES;
811 break;
812
813 default:
814 case EFI_DEVICE_ERROR:
815 pSocket->errno = EIO;
816 break;
817
818 case EFI_INVALID_PARAMETER:
819 pSocket->errno = EADDRNOTAVAIL;
820 break;
821
822 case EFI_NO_MAPPING:
823 pSocket->errno = EAFNOSUPPORT;
824 break;
825
826 case EFI_OUT_OF_RESOURCES:
827 pSocket->errno = ENOBUFS;
828 break;
829
830 case EFI_UNSUPPORTED:
831 pSocket->errno = EOPNOTSUPP;
832 break;
833 }
834 }
835 else {
836 DEBUG (( DEBUG_TX,
837 "0x%08x: pPort Configured for %d.%d.%d.%d --> %d.%d.%d.%d\r\n",
838 pPort,
839 pIp4->ModeData.ConfigData.StationAddress.Addr[0],
840 pIp4->ModeData.ConfigData.StationAddress.Addr[1],
841 pIp4->ModeData.ConfigData.StationAddress.Addr[2],
842 pIp4->ModeData.ConfigData.StationAddress.Addr[3],
843 pIp4->DestinationAddress.Addr[0],
844 pIp4->DestinationAddress.Addr[1],
845 pIp4->DestinationAddress.Addr[2],
846 pIp4->DestinationAddress.Addr[3]));
847 DEBUG (( DEBUG_TX,
848 "Subnet Mask: %d.%d.%d.%d\r\n",
849 pIp4->ModeData.ConfigData.SubnetMask.Addr[0],
850 pIp4->ModeData.ConfigData.SubnetMask.Addr[1],
851 pIp4->ModeData.ConfigData.SubnetMask.Addr[2],
852 pIp4->ModeData.ConfigData.SubnetMask.Addr[3]));
853 DEBUG (( DEBUG_TX,
854 "Route Count: %d\r\n",
855 pIp4->ModeData.RouteCount ));
856 for ( Index = 0; pIp4->ModeData.RouteCount > Index; Index++ ) {
857 if ( 0 == Index ) {
858 DEBUG (( DEBUG_TX, "Route Table:\r\n" ));
859 }
860 DEBUG (( DEBUG_TX,
861 "%5d: %d.%d.%d.%d, %d.%d.%d.%d ==> %d.%d.%d.%d\r\n",
862 Index,
863 pIp4->ModeData.RouteTable[Index].SubnetAddress.Addr[0],
864 pIp4->ModeData.RouteTable[Index].SubnetAddress.Addr[1],
865 pIp4->ModeData.RouteTable[Index].SubnetAddress.Addr[2],
866 pIp4->ModeData.RouteTable[Index].SubnetAddress.Addr[3],
867 pIp4->ModeData.RouteTable[Index].SubnetMask.Addr[0],
868 pIp4->ModeData.RouteTable[Index].SubnetMask.Addr[1],
869 pIp4->ModeData.RouteTable[Index].SubnetMask.Addr[2],
870 pIp4->ModeData.RouteTable[Index].SubnetMask.Addr[3],
871 pIp4->ModeData.RouteTable[Index].GatewayAddress.Addr[0],
872 pIp4->ModeData.RouteTable[Index].GatewayAddress.Addr[1],
873 pIp4->ModeData.RouteTable[Index].GatewayAddress.Addr[2],
874 pIp4->ModeData.RouteTable[Index].GatewayAddress.Addr[3]));
875 }
876 pPort->bConfigured = TRUE;
877
878 //
879 // Start the first read on the port
880 //
881 EslSocketRxStart ( pPort );
882
883 //
884 // The socket is connected
885 //
886 pSocket->State = SOCKET_STATE_CONNECTED;
887 }
888
889 //
890 // Set the next port
891 //
892 pPort = pNextPort;
893 }
894
895 //
896 // Determine the configuration status
897 //
898 if ( NULL != pSocket->pPortList ) {
899 pSocket->bConfigured = TRUE;
900 }
901 }
902
903 //
904 // Determine the socket configuration status
905 //
906 if ( !EFI_ERROR ( Status )) {
907 Status = pSocket->bConfigured ? EFI_SUCCESS : EFI_NOT_STARTED;
908 }
909
910 //
911 // Return the port connected state.
912 //
913 DBG_EXIT_STATUS ( Status );
914 return Status;
915 }
916
917
918 /**
919 Buffer data for transmission over a network connection.
920
921 This routine buffers data for the transmit engine in the normal
922 data queue. When the \ref TransmitEngine has resources, this
923 routine will start the transmission of the next buffer on the
924 network connection.
925
926 This routine is called by ::EslSocketTransmit to buffer
927 data for transmission. The data is copied into a local buffer
928 freeing the application buffer for reuse upon return. When
929 necessary, this routine starts the transmit engine that
930 performs the data transmission on the network connection. The
931 transmit engine transmits the data a packet at a time over the
932 network connection.
933
934 Transmission errors are returned during the next transmission or
935 during the close operation. Only buffering errors are returned
936 during the current transmission attempt.
937
938 @param [in] pSocket Address of an ::ESL_SOCKET structure
939
940 @param [in] Flags Message control flags
941
942 @param [in] BufferLength Length of the the buffer
943
944 @param [in] pBuffer Address of a buffer to receive the data.
945
946 @param [in] pDataLength Number of received data bytes in the buffer.
947
948 @param [in] pAddress Network address of the remote system address
949
950 @param [in] AddressLength Length of the remote network address structure
951
952 @retval EFI_SUCCESS - Socket data successfully buffered
953
954 **/
955 EFI_STATUS
956 EslIp4TxBuffer (
957 IN ESL_SOCKET * pSocket,
958 IN int Flags,
959 IN size_t BufferLength,
960 IN CONST UINT8 * pBuffer,
961 OUT size_t * pDataLength,
962 IN const struct sockaddr * pAddress,
963 IN socklen_t AddressLength
964 )
965 {
966 ESL_PACKET * pPacket;
967 ESL_PACKET * pPreviousPacket;
968 ESL_PORT * pPort;
969 const struct sockaddr_in * pRemoteAddress;
970 ESL_IP4_CONTEXT * pIp4;
971 size_t * pTxBytes;
972 ESL_IP4_TX_DATA * pTxData;
973 EFI_STATUS Status;
974 EFI_TPL TplPrevious;
975
976 DBG_ENTER ( );
977
978 //
979 // Assume failure
980 //
981 Status = EFI_UNSUPPORTED;
982 pSocket->errno = ENOTCONN;
983 *pDataLength = 0;
984
985 //
986 // Verify that the socket is connected
987 //
988 if ( SOCKET_STATE_CONNECTED == pSocket->State ) {
989 //
990 // Locate the port
991 //
992 pPort = pSocket->pPortList;
993 if ( NULL != pPort ) {
994 //
995 // Determine the queue head
996 //
997 pIp4 = &pPort->Context.Ip4;
998 pTxBytes = &pSocket->TxBytes;
999
1000 //
1001 // Verify that there is enough room to buffer another
1002 // transmit operation
1003 //
1004 if ( pSocket->MaxTxBuf > *pTxBytes ) {
1005 //
1006 // Attempt to allocate the packet
1007 //
1008 Status = EslSocketPacketAllocate ( &pPacket,
1009 sizeof ( pPacket->Op.Ip4Tx )
1010 - sizeof ( pPacket->Op.Ip4Tx.Buffer )
1011 + BufferLength,
1012 0,
1013 DEBUG_TX );
1014 if ( !EFI_ERROR ( Status )) {
1015 //
1016 // Initialize the transmit operation
1017 //
1018 pTxData = &pPacket->Op.Ip4Tx;
1019 pTxData->TxData.DestinationAddress.Addr[0] = pIp4->DestinationAddress.Addr[0];
1020 pTxData->TxData.DestinationAddress.Addr[1] = pIp4->DestinationAddress.Addr[1];
1021 pTxData->TxData.DestinationAddress.Addr[2] = pIp4->DestinationAddress.Addr[2];
1022 pTxData->TxData.DestinationAddress.Addr[3] = pIp4->DestinationAddress.Addr[3];
1023 pTxData->TxData.OverrideData = NULL;
1024 pTxData->TxData.OptionsLength = 0;
1025 pTxData->TxData.OptionsBuffer = NULL;
1026 pTxData->TxData.TotalDataLength = (UINT32) BufferLength;
1027 pTxData->TxData.FragmentCount = 1;
1028 pTxData->TxData.FragmentTable[0].FragmentLength = (UINT32) BufferLength;
1029 pTxData->TxData.FragmentTable[0].FragmentBuffer = &pPacket->Op.Ip4Tx.Buffer[0];
1030
1031 //
1032 // Set the remote system address if necessary
1033 //
1034 if ( NULL != pAddress ) {
1035 pRemoteAddress = (const struct sockaddr_in *)pAddress;
1036 pTxData->Override.SourceAddress.Addr[0] = pIp4->ModeData.ConfigData.StationAddress.Addr[0];
1037 pTxData->Override.SourceAddress.Addr[1] = pIp4->ModeData.ConfigData.StationAddress.Addr[1];
1038 pTxData->Override.SourceAddress.Addr[2] = pIp4->ModeData.ConfigData.StationAddress.Addr[2];
1039 pTxData->Override.SourceAddress.Addr[3] = pIp4->ModeData.ConfigData.StationAddress.Addr[3];
1040 pTxData->TxData.DestinationAddress.Addr[0] = (UINT8)pRemoteAddress->sin_addr.s_addr;
1041 pTxData->TxData.DestinationAddress.Addr[1] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 8 );
1042 pTxData->TxData.DestinationAddress.Addr[2] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 16 );
1043 pTxData->TxData.DestinationAddress.Addr[3] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 24 );
1044 pTxData->Override.GatewayAddress.Addr[0] = 0;
1045 pTxData->Override.GatewayAddress.Addr[1] = 0;
1046 pTxData->Override.GatewayAddress.Addr[2] = 0;
1047 pTxData->Override.GatewayAddress.Addr[3] = 0;
1048 pTxData->Override.Protocol = (UINT8)pSocket->Protocol;
1049 pTxData->Override.TypeOfService = 0;
1050 pTxData->Override.TimeToLive = 255;
1051 pTxData->Override.DoNotFragment = FALSE;
1052
1053 //
1054 // Use the remote system address when sending this packet
1055 //
1056 pTxData->TxData.OverrideData = &pTxData->Override;
1057 }
1058
1059 //
1060 // Copy the data into the buffer
1061 //
1062 CopyMem ( &pPacket->Op.Ip4Tx.Buffer[0],
1063 pBuffer,
1064 BufferLength );
1065
1066 //
1067 // Synchronize with the socket layer
1068 //
1069 RAISE_TPL ( TplPrevious, TPL_SOCKETS );
1070
1071 //
1072 // Stop transmission after an error
1073 //
1074 if ( !EFI_ERROR ( pSocket->TxError )) {
1075 //
1076 // Display the request
1077 //
1078 DEBUG (( DEBUG_TX,
1079 "Send %d bytes from 0x%08x, %d.%d.%d.%d --> %d.%d.%d.%d\r\n",
1080 BufferLength,
1081 pBuffer,
1082 pIp4->ModeData.ConfigData.StationAddress.Addr[0],
1083 pIp4->ModeData.ConfigData.StationAddress.Addr[1],
1084 pIp4->ModeData.ConfigData.StationAddress.Addr[2],
1085 pIp4->ModeData.ConfigData.StationAddress.Addr[3],
1086 pTxData->TxData.DestinationAddress.Addr[0],
1087 pTxData->TxData.DestinationAddress.Addr[1],
1088 pTxData->TxData.DestinationAddress.Addr[2],
1089 pTxData->TxData.DestinationAddress.Addr[3]));
1090
1091 //
1092 // Queue the data for transmission
1093 //
1094 pPacket->pNext = NULL;
1095 pPreviousPacket = pSocket->pTxPacketListTail;
1096 if ( NULL == pPreviousPacket ) {
1097 pSocket->pTxPacketListHead = pPacket;
1098 }
1099 else {
1100 pPreviousPacket->pNext = pPacket;
1101 }
1102 pSocket->pTxPacketListTail = pPacket;
1103 DEBUG (( DEBUG_TX,
1104 "0x%08x: Packet on transmit list\r\n",
1105 pPacket ));
1106
1107 //
1108 // Account for the buffered data
1109 //
1110 *pTxBytes += BufferLength;
1111 *pDataLength = BufferLength;
1112
1113 //
1114 // Start the transmit engine if it is idle
1115 //
1116 if ( NULL != pPort->pTxFree ) {
1117 EslSocketTxStart ( pPort,
1118 &pSocket->pTxPacketListHead,
1119 &pSocket->pTxPacketListTail,
1120 &pPort->pTxActive,
1121 &pPort->pTxFree );
1122 }
1123 }
1124 else {
1125 //
1126 // Previous transmit error
1127 // Stop transmission
1128 //
1129 Status = pSocket->TxError;
1130 pSocket->errno = EIO;
1131
1132 //
1133 // Free the packet
1134 //
1135 EslSocketPacketFree ( pPacket, DEBUG_TX );
1136 }
1137
1138 //
1139 // Release the socket layer synchronization
1140 //
1141 RESTORE_TPL ( TplPrevious );
1142 }
1143 else {
1144 //
1145 // Packet allocation failed
1146 //
1147 pSocket->errno = ENOMEM;
1148 }
1149 }
1150 else {
1151 //
1152 // Not enough buffer space available
1153 //
1154 pSocket->errno = EAGAIN;
1155 Status = EFI_NOT_READY;
1156 }
1157 }
1158 }
1159
1160 //
1161 // Return the operation status
1162 //
1163 DBG_EXIT_STATUS ( Status );
1164 return Status;
1165 }
1166
1167
1168 /**
1169 Process the transmit completion
1170
1171 This routine use ::EslSocketTxComplete to perform the transmit
1172 completion processing for data packets.
1173
1174 This routine is called by the IPv4 network layer when a data
1175 transmit request completes.
1176
1177 @param [in] Event The normal transmit completion event
1178
1179 @param [in] pIo The address of an ::ESL_IO_MGMT structure
1180
1181 **/
1182 VOID
1183 EslIp4TxComplete (
1184 IN EFI_EVENT Event,
1185 IN ESL_IO_MGMT * pIo
1186 )
1187 {
1188 UINT32 LengthInBytes;
1189 ESL_PORT * pPort;
1190 ESL_PACKET * pPacket;
1191 ESL_SOCKET * pSocket;
1192 EFI_STATUS Status;
1193
1194 DBG_ENTER ( );
1195
1196 //
1197 // Locate the active transmit packet
1198 //
1199 pPacket = pIo->pPacket;
1200 pPort = pIo->pPort;
1201 pSocket = pPort->pSocket;
1202
1203 //
1204 // Get the transmit length and status
1205 //
1206 LengthInBytes = pPacket->Op.Ip4Tx.TxData.TotalDataLength;
1207 pSocket->TxBytes -= LengthInBytes;
1208 Status = pIo->Token.Ip4Tx.Status;
1209
1210 //
1211 // Complete the transmit operation
1212 //
1213 EslSocketTxComplete ( pIo,
1214 LengthInBytes,
1215 Status,
1216 "Raw ",
1217 &pSocket->pTxPacketListHead,
1218 &pSocket->pTxPacketListTail,
1219 &pPort->pTxActive,
1220 &pPort->pTxFree );
1221 DBG_EXIT ( );
1222 }
1223
1224
1225 /**
1226 Interface between the socket layer and the network specific
1227 code that supports SOCK_RAW sockets over IPv4.
1228 **/
1229 CONST ESL_PROTOCOL_API cEslIp4Api = {
1230 "IPv4",
1231 IPPROTO_IP,
1232 OFFSET_OF ( ESL_PORT, Context.Ip4.ModeData.ConfigData ),
1233 OFFSET_OF ( ESL_LAYER, pIp4List ),
1234 OFFSET_OF ( struct sockaddr_in, sin_zero ),
1235 sizeof ( struct sockaddr_in ),
1236 AF_INET,
1237 sizeof (((ESL_PACKET *)0 )->Op.Ip4Rx ),
1238 sizeof (((ESL_PACKET *)0 )->Op.Ip4Rx ),
1239 OFFSET_OF ( ESL_IO_MGMT, Token.Ip4Rx.Packet.RxData ),
1240 FALSE,
1241 EADDRNOTAVAIL,
1242 NULL, // Accept
1243 NULL, // ConnectPoll
1244 NULL, // ConnectStart
1245 EslIp4SocketIsConfigured,
1246 EslIp4LocalAddressGet,
1247 EslIp4LocalAddressSet,
1248 NULL, // Listen
1249 EslIp4OptionGet,
1250 EslIp4OptionSet,
1251 EslIp4PacketFree,
1252 EslIp4PortAllocate,
1253 NULL, // PortClose
1254 NULL, // PortCloseOp
1255 TRUE,
1256 EslIp4Receive,
1257 EslIp4RemoteAddressGet,
1258 EslIp4RemoteAddressSet,
1259 EslIp4RxComplete,
1260 NULL, // RxStart
1261 EslIp4TxBuffer,
1262 EslIp4TxComplete,
1263 NULL // TxOobComplete
1264 };