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