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