]> git.proxmox.com Git - mirror_edk2.git/blame - StdLib/EfiSocketLib/Udp6.c
Fix a bug about the iSCSI DHCP dependency issue.
[mirror_edk2.git] / StdLib / EfiSocketLib / Udp6.c
CommitLineData
3bdf9aae 1/** @file\r
2 Implement the UDP4 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 IPv6 address and UDP port number associated\r
22 with the local socket.\r
23\r
24 This routine is called by ::EslSocketGetLocalAddress to determine the\r
25 network address for the SOCK_DGRAM socket.\r
26\r
27 @param [in] pPort Address of an ::ESL_PORT structure.\r
28\r
29 @param [out] pSockAddr Network address to receive the local system address\r
30\r
31**/\r
32VOID\r
33EslUdp6LocalAddressGet (\r
34 IN ESL_PORT * pPort,\r
35 OUT struct sockaddr * pSockAddr\r
36 )\r
37{\r
38 struct sockaddr_in6 * pLocalAddress;\r
39 ESL_UDP6_CONTEXT * pUdp6;\r
40\r
41 DBG_ENTER ( );\r
42\r
43 //\r
44 // Return the local address\r
45 //\r
46 pUdp6 = &pPort->Context.Udp6;\r
47 pLocalAddress = (struct sockaddr_in6 *)pSockAddr;\r
48 pLocalAddress->sin6_family = AF_INET6;\r
49 pLocalAddress->sin6_port = SwapBytes16 ( pUdp6->ConfigData.StationPort );\r
50 CopyMem ( &pLocalAddress->sin6_addr,\r
51 &pUdp6->ConfigData.StationAddress.Addr[0],\r
52 sizeof ( pLocalAddress->sin6_addr ));\r
53\r
54 DBG_EXIT ( );\r
55}\r
56\r
57\r
58/**\r
59 Set the local port address.\r
60\r
61 This routine sets the local port address.\r
62\r
63 This support routine is called by ::EslSocketPortAllocate.\r
64\r
65 @param [in] pPort Address of an ESL_PORT structure\r
66 @param [in] pSockAddr Address of a sockaddr structure that contains the\r
67 connection point on the local machine. An IPv6 address\r
68 of INADDR_ANY specifies that the connection is made to\r
69 all of the network stacks on the platform. Specifying a\r
70 specific IPv6 address restricts the connection to the\r
71 network stack supporting that address. Specifying zero\r
72 for the port causes the network layer to assign a port\r
73 number from the dynamic range. Specifying a specific\r
74 port number causes the network layer to use that port.\r
75\r
76 @param [in] bBindTest TRUE = run bind testing\r
77\r
78 @retval EFI_SUCCESS The operation was successful\r
79\r
80 **/\r
81EFI_STATUS\r
82EslUdp6LocalAddressSet (\r
83 IN ESL_PORT * pPort,\r
84 IN CONST struct sockaddr * pSockAddr,\r
85 IN BOOLEAN bBindTest\r
86 )\r
87{\r
88 EFI_UDP6_CONFIG_DATA * pConfig;\r
89 CONST struct sockaddr_in6 * pIpAddress;\r
90 CONST UINT8 * pIPv6Address;\r
91 EFI_STATUS Status;\r
92\r
93 DBG_ENTER ( );\r
94\r
95 //\r
96 // Set the local address\r
97 //\r
98 pIpAddress = (struct sockaddr_in6 *)pSockAddr;\r
99 pIPv6Address = (UINT8 *)&pIpAddress->sin6_addr;\r
100 pConfig = &pPort->Context.Udp6.ConfigData;\r
101 CopyMem ( &pConfig->StationAddress,\r
102 pIPv6Address,\r
103 sizeof ( pConfig->StationAddress ));\r
104\r
105 //\r
106 // Validate the IP address\r
107 //\r
108 pConfig->StationPort = 0;\r
109 Status = bBindTest ? EslSocketBindTest ( pPort, EADDRNOTAVAIL )\r
110 : EFI_SUCCESS;\r
111 if ( !EFI_ERROR ( Status )) {\r
112 //\r
113 // Set the port number\r
114 //\r
115 pConfig->StationPort = SwapBytes16 ( pIpAddress->sin6_port );\r
f74dc4bb 116 pPort->pSocket->bAddressSet = TRUE;\r
3bdf9aae 117\r
118 //\r
119 // Display the local address\r
120 //\r
121 DEBUG (( DEBUG_BIND,\r
122 "0x%08x: Port, Local UDP6 Address: [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",\r
123 pPort,\r
124 pConfig->StationAddress.Addr[0],\r
125 pConfig->StationAddress.Addr[1],\r
126 pConfig->StationAddress.Addr[2],\r
127 pConfig->StationAddress.Addr[3],\r
128 pConfig->StationAddress.Addr[4],\r
129 pConfig->StationAddress.Addr[5],\r
130 pConfig->StationAddress.Addr[6],\r
131 pConfig->StationAddress.Addr[7],\r
132 pConfig->StationAddress.Addr[8],\r
133 pConfig->StationAddress.Addr[9],\r
134 pConfig->StationAddress.Addr[10],\r
135 pConfig->StationAddress.Addr[11],\r
136 pConfig->StationAddress.Addr[12],\r
137 pConfig->StationAddress.Addr[13],\r
138 pConfig->StationAddress.Addr[14],\r
139 pConfig->StationAddress.Addr[15],\r
140 pConfig->StationPort ));\r
141 }\r
142\r
143 //\r
144 // Return the operation status\r
145 //\r
146 DBG_EXIT_STATUS ( Status );\r
147 return Status;\r
148}\r
149\r
150\r
151/**\r
152 Free a receive packet\r
153\r
154 This routine performs the network specific operations necessary\r
155 to free a receive packet.\r
156\r
157 This routine is called by ::EslSocketPortCloseTxDone to free a\r
158 receive packet.\r
159\r
160 @param [in] pPacket Address of an ::ESL_PACKET structure.\r
161 @param [in, out] pRxBytes Address of the count of RX bytes\r
162\r
163**/\r
164VOID\r
165EslUdp6PacketFree (\r
166 IN ESL_PACKET * pPacket,\r
167 IN OUT size_t * pRxBytes\r
168 )\r
169{\r
170 EFI_UDP6_RECEIVE_DATA * pRxData;\r
171\r
172 DBG_ENTER ( );\r
173\r
174 //\r
175 // Account for the receive bytes\r
176 //\r
177 pRxData = pPacket->Op.Udp6Rx.pRxData;\r
178 *pRxBytes -= pRxData->DataLength;\r
179\r
180 //\r
181 // Disconnect the buffer from the packet\r
182 //\r
183 pPacket->Op.Udp6Rx.pRxData = NULL;\r
184\r
185 //\r
186 // Return the buffer to the UDP6 driver\r
187 //\r
188 gBS->SignalEvent ( pRxData->RecycleSignal );\r
189 DBG_EXIT ( );\r
190}\r
191\r
192\r
193/**\r
194 Initialize the network specific portions of an ::ESL_PORT structure.\r
195\r
196 This routine initializes the network specific portions of an\r
197 ::ESL_PORT structure for use by the socket.\r
198\r
199 This support routine is called by ::EslSocketPortAllocate\r
200 to connect the socket with the underlying network adapter\r
201 running the UDPv4 protocol.\r
202\r
203 @param [in] pPort Address of an ESL_PORT structure\r
204 @param [in] DebugFlags Flags for debug messages\r
205\r
206 @retval EFI_SUCCESS - Socket successfully created\r
207\r
208 **/\r
209EFI_STATUS\r
210EslUdp6PortAllocate (\r
211 IN ESL_PORT * pPort,\r
212 IN UINTN DebugFlags\r
213 )\r
214{\r
215 EFI_UDP6_CONFIG_DATA * pConfig;\r
216 ESL_SOCKET * pSocket;\r
217 EFI_STATUS Status;\r
218\r
219 DBG_ENTER ( );\r
220\r
221 //\r
222 // Initialize the port\r
223 //\r
224 pSocket = pPort->pSocket;\r
225 pSocket->TxPacketOffset = OFFSET_OF ( ESL_PACKET, Op.Udp6Tx.TxData );\r
226 pSocket->TxTokenEventOffset = OFFSET_OF ( ESL_IO_MGMT, Token.Udp6Tx.Event );\r
227 pSocket->TxTokenOffset = OFFSET_OF ( EFI_UDP6_COMPLETION_TOKEN, Packet.TxData );\r
228\r
229 //\r
230 // Save the cancel, receive and transmit addresses\r
231 //\r
232 pPort->pfnConfigure = (PFN_NET_CONFIGURE)pPort->pProtocol.UDPv6->Configure;\r
233 pPort->pfnRxCancel = (PFN_NET_IO_START)pPort->pProtocol.UDPv6->Cancel;\r
234 pPort->pfnRxPoll = (PFN_NET_POLL)pPort->pProtocol.UDPv6->Poll;\r
235 pPort->pfnRxStart = (PFN_NET_IO_START)pPort->pProtocol.UDPv6->Receive;\r
236 pPort->pfnTxStart = (PFN_NET_IO_START)pPort->pProtocol.UDPv6->Transmit;\r
237\r
238 //\r
239 // Do not drop packets\r
240 //\r
241 pConfig = &pPort->Context.Udp6.ConfigData;\r
242 pConfig->ReceiveTimeout = 0;\r
243 pConfig->ReceiveTimeout = pConfig->ReceiveTimeout;\r
244\r
245 //\r
246 // Set the configuration flags\r
247 //\r
248 pConfig->AllowDuplicatePort = TRUE;\r
249 pConfig->AcceptAnyPort = FALSE;\r
250 pConfig->AcceptPromiscuous = FALSE;\r
251 pConfig->HopLimit = 255;\r
252 pConfig->TrafficClass = 0;\r
253\r
254 Status = EFI_SUCCESS;\r
255\r
256 //\r
257 // Return the operation status\r
258 //\r
259 DBG_EXIT_STATUS ( Status );\r
260 return Status;\r
261}\r
262\r
263\r
264/**\r
265 Receive data from a network connection.\r
266\r
267 This routine attempts to return buffered data to the caller. The\r
268 data is removed from the urgent queue if the message flag MSG_OOB\r
269 is specified, otherwise data is removed from the normal queue.\r
270 See the \ref ReceiveEngine section.\r
271\r
272 This routine is called by ::EslSocketReceive to handle the network\r
273 specific receive operation to support SOCK_DGRAM sockets.\r
274\r
275 @param [in] pPort Address of an ::ESL_PORT structure.\r
276\r
277 @param [in] pPacket Address of an ::ESL_PACKET structure.\r
278 \r
279 @param [in] pbConsumePacket Address of a BOOLEAN indicating if the packet is to be consumed\r
280 \r
281 @param [in] BufferLength Length of the the buffer\r
282 \r
283 @param [in] pBuffer Address of a buffer to receive the data.\r
284 \r
285 @param [in] pDataLength Number of received data bytes in the buffer.\r
286\r
287 @param [out] pAddress Network address to receive the remote system address\r
288\r
289 @param [out] pSkipBytes Address to receive the number of bytes skipped\r
290\r
291 @return Returns the address of the next free byte in the buffer.\r
292\r
293 **/\r
294UINT8 *\r
295EslUdp6Receive (\r
296 IN ESL_PORT * pPort,\r
297 IN ESL_PACKET * pPacket,\r
298 IN BOOLEAN * pbConsumePacket,\r
299 IN size_t BufferLength,\r
300 IN UINT8 * pBuffer,\r
301 OUT size_t * pDataLength,\r
302 OUT struct sockaddr * pAddress,\r
303 OUT size_t * pSkipBytes\r
304 )\r
305{\r
306 size_t DataBytes;\r
307 struct sockaddr_in6 * pRemoteAddress;\r
308 EFI_UDP6_RECEIVE_DATA * pRxData;\r
309\r
310 DBG_ENTER ( );\r
311\r
312 pRxData = pPacket->Op.Udp6Rx.pRxData;\r
313 //\r
314 // Return the remote system address if requested\r
315 //\r
316 if ( NULL != pAddress ) {\r
317 //\r
318 // Build the remote address\r
319 //\r
320 DEBUG (( DEBUG_RX,\r
321 "Getting packet remote address: [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",\r
322 pRxData->UdpSession.SourceAddress.Addr[0],\r
323 pRxData->UdpSession.SourceAddress.Addr[1],\r
324 pRxData->UdpSession.SourceAddress.Addr[2],\r
325 pRxData->UdpSession.SourceAddress.Addr[3],\r
326 pRxData->UdpSession.SourceAddress.Addr[4],\r
327 pRxData->UdpSession.SourceAddress.Addr[5],\r
328 pRxData->UdpSession.SourceAddress.Addr[6],\r
329 pRxData->UdpSession.SourceAddress.Addr[7],\r
330 pRxData->UdpSession.SourceAddress.Addr[8],\r
331 pRxData->UdpSession.SourceAddress.Addr[9],\r
332 pRxData->UdpSession.SourceAddress.Addr[10],\r
333 pRxData->UdpSession.SourceAddress.Addr[11],\r
334 pRxData->UdpSession.SourceAddress.Addr[12],\r
335 pRxData->UdpSession.SourceAddress.Addr[13],\r
336 pRxData->UdpSession.SourceAddress.Addr[14],\r
337 pRxData->UdpSession.SourceAddress.Addr[15],\r
338 pRxData->UdpSession.SourcePort ));\r
339 pRemoteAddress = (struct sockaddr_in6 *)pAddress;\r
340 CopyMem ( &pRemoteAddress->sin6_addr,\r
341 &pRxData->UdpSession.SourceAddress.Addr[0],\r
342 sizeof ( pRemoteAddress->sin6_addr ));\r
343 pRemoteAddress->sin6_port = SwapBytes16 ( pRxData->UdpSession.SourcePort );\r
344 }\r
345\r
346 //\r
347 // Copy the received data\r
348 //\r
349 pBuffer = EslSocketCopyFragmentedBuffer ( pRxData->FragmentCount,\r
350 (EFI_IP4_FRAGMENT_DATA *)&pRxData->FragmentTable[0],\r
351 BufferLength,\r
352 pBuffer,\r
353 &DataBytes );\r
354\r
355 //\r
356 // Determine if the data is being read\r
357 //\r
358 if ( *pbConsumePacket ) {\r
359 //\r
360 // Display for the bytes consumed\r
361 //\r
362 DEBUG (( DEBUG_RX,\r
363 "0x%08x: Port account for 0x%08x bytes\r\n",\r
364 pPort,\r
365 DataBytes ));\r
366\r
367 //\r
368 // Account for any discarded data\r
369 //\r
370 *pSkipBytes = pRxData->DataLength - DataBytes;\r
371 }\r
372\r
373 //\r
374 // Return the data length and the buffer address\r
375 //\r
376 *pDataLength = DataBytes;\r
377 DBG_EXIT_HEX ( pBuffer );\r
378 return pBuffer;\r
379}\r
380\r
381\r
382/**\r
383 Get the remote socket address\r
384\r
385 This routine returns the address of the remote connection point\r
386 associated with the SOCK_DGRAM socket.\r
387\r
388 This routine is called by ::EslSocketGetPeerAddress to detemine\r
389 the UDPv4 address and port number associated with the network adapter.\r
390\r
391 @param [in] pPort Address of an ::ESL_PORT structure.\r
392\r
393 @param [out] pAddress Network address to receive the remote system address\r
394\r
395**/\r
396VOID\r
397EslUdp6RemoteAddressGet (\r
398 IN ESL_PORT * pPort,\r
399 OUT struct sockaddr * pAddress\r
400 )\r
401{\r
402 struct sockaddr_in6 * pRemoteAddress;\r
403 ESL_UDP6_CONTEXT * pUdp6;\r
404\r
405 DBG_ENTER ( );\r
406\r
407 //\r
408 // Return the remote address\r
409 //\r
410 pUdp6 = &pPort->Context.Udp6;\r
411 pRemoteAddress = (struct sockaddr_in6 *)pAddress;\r
412 pRemoteAddress->sin6_family = AF_INET6;\r
413 pRemoteAddress->sin6_port = SwapBytes16 ( pUdp6->ConfigData.RemotePort );\r
414 CopyMem ( &pRemoteAddress->sin6_addr,\r
415 &pUdp6->ConfigData.RemoteAddress.Addr[0],\r
416 sizeof ( pRemoteAddress->sin6_addr ));\r
417\r
418 DBG_EXIT ( );\r
419}\r
420\r
421\r
422/**\r
423 Set the remote address\r
424\r
425 This routine sets the remote address in the port.\r
426\r
427 This routine is called by ::EslSocketConnect to specify the\r
428 remote network address.\r
429\r
430 @param [in] pPort Address of an ::ESL_PORT structure.\r
431\r
432 @param [in] pSockAddr Network address of the remote system.\r
433\r
434 @param [in] SockAddrLength Length in bytes of the network address.\r
435\r
436 @retval EFI_SUCCESS The operation was successful\r
437\r
438 **/\r
439EFI_STATUS\r
440EslUdp6RemoteAddressSet (\r
441 IN ESL_PORT * pPort,\r
442 IN CONST struct sockaddr * pSockAddr,\r
443 IN socklen_t SockAddrLength\r
444 )\r
445{\r
446 CONST struct sockaddr_in6 * pRemoteAddress;\r
447 ESL_UDP6_CONTEXT * pUdp6;\r
448 EFI_STATUS Status;\r
449\r
450 DBG_ENTER ( );\r
451\r
452 //\r
453 // Set the remote address\r
454 //\r
455 pUdp6 = &pPort->Context.Udp6;\r
456 pRemoteAddress = (struct sockaddr_in6 *)pSockAddr;\r
457 CopyMem ( &pUdp6->ConfigData.RemoteAddress,\r
458 &pRemoteAddress->sin6_addr,\r
459 sizeof ( pUdp6->ConfigData.RemoteAddress ));\r
460 pUdp6->ConfigData.RemotePort = SwapBytes16 ( pRemoteAddress->sin6_port );\r
461 Status = EFI_SUCCESS;\r
462\r
463 //\r
464 // Return the operation status\r
465 //\r
466 DBG_EXIT_STATUS ( Status );\r
467 return Status;\r
468}\r
469\r
470\r
471/**\r
472 Process the receive completion\r
473\r
474 This routine keeps the UDPv4 driver's buffer and queues it in\r
475 in FIFO order to the data queue. The UDP6 driver's buffer will\r
476 be returned by either ::EslUdp6Receive or ::EslSocketPortCloseTxDone.\r
477 See the \ref ReceiveEngine section.\r
478\r
479 This routine is called by the UDPv4 driver when data is\r
480 received.\r
481\r
482 @param [in] Event The receive completion event\r
483\r
484 @param [in] pIo Address of an ::ESL_IO_MGMT structure\r
485\r
486**/\r
487VOID\r
488EslUdp6RxComplete (\r
489 IN EFI_EVENT Event,\r
490 IN ESL_IO_MGMT * pIo\r
491 )\r
492{\r
493 size_t LengthInBytes;\r
494 ESL_PACKET * pPacket;\r
495 EFI_UDP6_RECEIVE_DATA * pRxData;\r
496 EFI_STATUS Status;\r
497 \r
498 DBG_ENTER ( );\r
499\r
500 //\r
501 // Get the operation status.\r
502 //\r
503 Status = pIo->Token.Udp6Rx.Status;\r
504 \r
505 //\r
506 // Get the packet length\r
507 //\r
508 pRxData = pIo->Token.Udp6Rx.Packet.RxData;\r
509 LengthInBytes = pRxData->DataLength;\r
510\r
511 //\r
512 // +--------------------+ +-----------------------+\r
513 // | ESL_IO_MGMT | | Data Buffer |\r
514 // | | | (Driver owned) |\r
515 // | +---------------+ +-----------------------+\r
516 // | | Token | ^\r
517 // | | Rx Event | |\r
518 // | | | +-----------------------+\r
519 // | | RxData --> | EFI_UDP6_RECEIVE_DATA |\r
520 // +----+---------------+ | (Driver owned) |\r
521 // +-----------------------+\r
522 // +--------------------+ ^\r
523 // | ESL_PACKET | .\r
524 // | | .\r
525 // | +---------------+ .\r
526 // | | pRxData --> NULL .......\r
527 // +----+---------------+\r
528 //\r
529 //\r
530 // Save the data in the packet\r
531 //\r
532 pPacket = pIo->pPacket;\r
533 pPacket->Op.Udp6Rx.pRxData = pRxData;\r
534\r
535 //\r
536 // Complete this request\r
537 //\r
538 EslSocketRxComplete ( pIo, Status, LengthInBytes, FALSE );\r
539 DBG_EXIT ( );\r
540}\r
541\r
542\r
543/**\r
544 Determine if the socket is configured.\r
545\r
546 This routine uses the flag ESL_SOCKET::bConfigured to determine\r
547 if the network layer's configuration routine has been called.\r
548 This routine calls the bind and configuration routines if they\r
549 were not already called. After the port is configured, the\r
550 \ref ReceiveEngine is started.\r
551\r
552 This routine is called by EslSocketIsConfigured to verify\r
553 that the socket is configured.\r
554\r
555 @param [in] pSocket Address of an ::ESL_SOCKET structure\r
556\r
557 @retval EFI_SUCCESS - The port is connected\r
558 @retval EFI_NOT_STARTED - The port is not connected\r
559\r
560 **/\r
561 EFI_STATUS\r
562 EslUdp6SocketIsConfigured (\r
563 IN ESL_SOCKET * pSocket\r
564 )\r
565{\r
566 EFI_UDP6_CONFIG_DATA * pConfigData;\r
567 ESL_PORT * pPort;\r
568 ESL_PORT * pNextPort;\r
569 ESL_UDP6_CONTEXT * pUdp6;\r
570 EFI_UDP6_PROTOCOL * pUdp6Protocol;\r
571 EFI_STATUS Status;\r
572 struct sockaddr_in6 LocalAddress;\r
573\r
574 DBG_ENTER ( );\r
575\r
576 //\r
577 // Assume success\r
578 //\r
579 Status = EFI_SUCCESS;\r
580\r
581 //\r
582 // Configure the port if necessary\r
583 //\r
584 if ( !pSocket->bConfigured ) {\r
585 //\r
586 // Fill in the port list if necessary\r
587 //\r
bb3aa953 588 pSocket->errno = ENETDOWN;\r
3bdf9aae 589 if ( NULL == pSocket->pPortList ) {\r
590 ZeroMem ( &LocalAddress, sizeof ( LocalAddress ));\r
591 LocalAddress.sin6_len = sizeof ( LocalAddress );\r
592 LocalAddress.sin6_family = AF_INET6;\r
593 Status = EslSocketBind ( &pSocket->SocketProtocol,\r
594 (struct sockaddr *)&LocalAddress,\r
595 LocalAddress.sin6_len,\r
596 &pSocket->errno );\r
597 }\r
598\r
599 //\r
600 // Walk the port list\r
601 //\r
602 pPort = pSocket->pPortList;\r
603 while ( NULL != pPort ) {\r
604 //\r
605 // Attempt to configure the port\r
606 //\r
607 pNextPort = pPort->pLinkSocket;\r
608 pUdp6 = &pPort->Context.Udp6;\r
609 pUdp6Protocol = pPort->pProtocol.UDPv6;\r
610 pConfigData = &pUdp6->ConfigData;\r
611 DEBUG (( DEBUG_TX,\r
612 "0x%08x: pPort Configuring for [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d --> [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",\r
613 pPort,\r
614 pConfigData->StationAddress.Addr[0],\r
615 pConfigData->StationAddress.Addr[1],\r
616 pConfigData->StationAddress.Addr[2],\r
617 pConfigData->StationAddress.Addr[3],\r
618 pConfigData->StationAddress.Addr[4],\r
619 pConfigData->StationAddress.Addr[5],\r
620 pConfigData->StationAddress.Addr[6],\r
621 pConfigData->StationAddress.Addr[7],\r
622 pConfigData->StationAddress.Addr[8],\r
623 pConfigData->StationAddress.Addr[9],\r
624 pConfigData->StationAddress.Addr[10],\r
625 pConfigData->StationAddress.Addr[11],\r
626 pConfigData->StationAddress.Addr[12],\r
627 pConfigData->StationAddress.Addr[13],\r
628 pConfigData->StationAddress.Addr[14],\r
629 pConfigData->StationAddress.Addr[15],\r
630 pConfigData->StationPort,\r
631 pConfigData->RemoteAddress.Addr[0],\r
632 pConfigData->RemoteAddress.Addr[1],\r
633 pConfigData->RemoteAddress.Addr[2],\r
634 pConfigData->RemoteAddress.Addr[3],\r
635 pConfigData->RemoteAddress.Addr[4],\r
636 pConfigData->RemoteAddress.Addr[5],\r
637 pConfigData->RemoteAddress.Addr[6],\r
638 pConfigData->RemoteAddress.Addr[7],\r
639 pConfigData->RemoteAddress.Addr[8],\r
640 pConfigData->RemoteAddress.Addr[9],\r
641 pConfigData->RemoteAddress.Addr[10],\r
642 pConfigData->RemoteAddress.Addr[11],\r
643 pConfigData->RemoteAddress.Addr[12],\r
644 pConfigData->RemoteAddress.Addr[13],\r
645 pConfigData->RemoteAddress.Addr[14],\r
646 pConfigData->RemoteAddress.Addr[15],\r
647 pConfigData->RemotePort ));\r
648 Status = pUdp6Protocol->Configure ( pUdp6Protocol,\r
649 pConfigData );\r
650 if ( !EFI_ERROR ( Status )) {\r
651 //\r
652 // Update the configuration data\r
653 //\r
654 Status = pUdp6Protocol->GetModeData ( pUdp6Protocol,\r
655 pConfigData,\r
656 NULL,\r
657 NULL,\r
658 NULL );\r
659 }\r
660 if ( EFI_ERROR ( Status )) {\r
bb3aa953 661 if ( !pSocket->bConfigured ) {\r
662 DEBUG (( DEBUG_LISTEN,\r
663 "ERROR - Failed to configure the Udp6 port, Status: %r\r\n",\r
664 Status ));\r
665 switch ( Status ) {\r
666 case EFI_ACCESS_DENIED:\r
667 pSocket->errno = EACCES;\r
668 break;\r
669\r
670 default:\r
671 case EFI_DEVICE_ERROR:\r
672 pSocket->errno = EIO;\r
673 break;\r
674\r
675 case EFI_INVALID_PARAMETER:\r
676 pSocket->errno = EADDRNOTAVAIL;\r
677 break;\r
678\r
679 case EFI_NO_MAPPING:\r
680 pSocket->errno = EAFNOSUPPORT;\r
681 break;\r
682\r
683 case EFI_OUT_OF_RESOURCES:\r
684 pSocket->errno = ENOBUFS;\r
685 break;\r
686\r
687 case EFI_UNSUPPORTED:\r
688 pSocket->errno = EOPNOTSUPP;\r
689 break;\r
690 }\r
3bdf9aae 691 }\r
692 }\r
693 else {\r
694 DEBUG (( DEBUG_TX,\r
695 "0x%08x: pPort Configured for [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d --> [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",\r
696 pPort,\r
697 pConfigData->StationAddress.Addr[0],\r
698 pConfigData->StationAddress.Addr[1],\r
699 pConfigData->StationAddress.Addr[2],\r
700 pConfigData->StationAddress.Addr[3],\r
701 pConfigData->StationAddress.Addr[4],\r
702 pConfigData->StationAddress.Addr[5],\r
703 pConfigData->StationAddress.Addr[6],\r
704 pConfigData->StationAddress.Addr[7],\r
705 pConfigData->StationAddress.Addr[8],\r
706 pConfigData->StationAddress.Addr[9],\r
707 pConfigData->StationAddress.Addr[10],\r
708 pConfigData->StationAddress.Addr[11],\r
709 pConfigData->StationAddress.Addr[12],\r
710 pConfigData->StationAddress.Addr[13],\r
711 pConfigData->StationAddress.Addr[14],\r
712 pConfigData->StationAddress.Addr[15],\r
713 pConfigData->StationPort,\r
714 pConfigData->RemoteAddress.Addr[0],\r
715 pConfigData->RemoteAddress.Addr[1],\r
716 pConfigData->RemoteAddress.Addr[2],\r
717 pConfigData->RemoteAddress.Addr[3],\r
718 pConfigData->RemoteAddress.Addr[4],\r
719 pConfigData->RemoteAddress.Addr[5],\r
720 pConfigData->RemoteAddress.Addr[6],\r
721 pConfigData->RemoteAddress.Addr[7],\r
722 pConfigData->RemoteAddress.Addr[8],\r
723 pConfigData->RemoteAddress.Addr[9],\r
724 pConfigData->RemoteAddress.Addr[10],\r
725 pConfigData->RemoteAddress.Addr[11],\r
726 pConfigData->RemoteAddress.Addr[12],\r
727 pConfigData->RemoteAddress.Addr[13],\r
728 pConfigData->RemoteAddress.Addr[14],\r
729 pConfigData->RemoteAddress.Addr[15],\r
730 pConfigData->RemotePort ));\r
731 pPort->bConfigured = TRUE;\r
bb3aa953 732 pSocket->bConfigured = TRUE;\r
3bdf9aae 733\r
734 //\r
735 // Start the first read on the port\r
736 //\r
737 EslSocketRxStart ( pPort );\r
738\r
739 //\r
740 // The socket is connected\r
741 //\r
742 pSocket->State = SOCKET_STATE_CONNECTED;\r
bb3aa953 743 pSocket->errno = 0;\r
3bdf9aae 744 }\r
745\r
746 //\r
747 // Set the next port\r
748 //\r
749 pPort = pNextPort;\r
750 }\r
3bdf9aae 751 }\r
752\r
753 //\r
754 // Determine the socket configuration status\r
755 //\r
bb3aa953 756 Status = pSocket->bConfigured ? EFI_SUCCESS : EFI_NOT_STARTED;\r
3bdf9aae 757 \r
758 //\r
759 // Return the port connected state.\r
760 //\r
761 DBG_EXIT_STATUS ( Status );\r
762 return Status;\r
763}\r
764\r
765\r
766/**\r
767 Buffer data for transmission over a network connection.\r
768\r
769 This routine buffers data for the transmit engine in the normal\r
770 data queue. When the \ref TransmitEngine has resources, this\r
771 routine will start the transmission of the next buffer on the\r
772 network connection.\r
773\r
774 This routine is called by ::EslSocketTransmit to buffer\r
775 data for transmission. The data is copied into a local buffer\r
776 freeing the application buffer for reuse upon return. When\r
777 necessary, this routine starts the transmit engine that\r
778 performs the data transmission on the network connection. The\r
779 transmit engine transmits the data a packet at a time over the\r
780 network connection.\r
781\r
782 Transmission errors are returned during the next transmission or\r
783 during the close operation. Only buffering errors are returned\r
784 during the current transmission attempt.\r
785\r
786 @param [in] pSocket Address of an ::ESL_SOCKET structure\r
787\r
788 @param [in] Flags Message control flags\r
789\r
790 @param [in] BufferLength Length of the the buffer\r
791\r
792 @param [in] pBuffer Address of a buffer to receive the data.\r
793\r
794 @param [in] pDataLength Number of received data bytes in the buffer.\r
795\r
796 @param [in] pAddress Network address of the remote system address\r
797\r
798 @param [in] AddressLength Length of the remote network address structure\r
799\r
800 @retval EFI_SUCCESS - Socket data successfully buffered\r
801\r
802**/\r
803EFI_STATUS\r
804EslUdp6TxBuffer (\r
805 IN ESL_SOCKET * pSocket,\r
806 IN int Flags,\r
807 IN size_t BufferLength,\r
808 IN CONST UINT8 * pBuffer,\r
809 OUT size_t * pDataLength,\r
810 IN const struct sockaddr * pAddress,\r
811 IN socklen_t AddressLength\r
812 )\r
813{\r
814 ESL_PACKET * pPacket;\r
815 ESL_PACKET * pPreviousPacket;\r
816 ESL_PORT * pPort;\r
817 const struct sockaddr_in6 * pRemoteAddress;\r
818 ESL_UDP6_CONTEXT * pUdp6;\r
819 size_t * pTxBytes;\r
820 ESL_UDP6_TX_DATA * pTxData;\r
821 EFI_STATUS Status;\r
822 EFI_TPL TplPrevious;\r
823\r
824 DBG_ENTER ( );\r
825\r
826 //\r
827 // Assume failure\r
828 //\r
829 Status = EFI_UNSUPPORTED;\r
830 pSocket->errno = ENOTCONN;\r
831 *pDataLength = 0;\r
832\r
833 //\r
834 // Verify that the socket is connected\r
835 //\r
836 if ( SOCKET_STATE_CONNECTED == pSocket->State ) {\r
837 //\r
884ed923 838 // Verify that there is enough room to buffer another\r
839 // transmit operation\r
3bdf9aae 840 //\r
884ed923 841 pTxBytes = &pSocket->TxBytes;\r
842 if ( pSocket->MaxTxBuf > *pTxBytes ) {\r
3bdf9aae 843 //\r
884ed923 844 // Locate the port\r
3bdf9aae 845 //\r
884ed923 846 pPort = pSocket->pPortList;\r
847 while ( NULL != pPort ) {\r
848 //\r
849 // Determine the queue head\r
850 //\r
851 pUdp6 = &pPort->Context.Udp6;\r
3bdf9aae 852\r
3bdf9aae 853 //\r
854 // Attempt to allocate the packet\r
855 //\r
856 Status = EslSocketPacketAllocate ( &pPacket,\r
857 sizeof ( pPacket->Op.Udp6Tx )\r
858 - sizeof ( pPacket->Op.Udp6Tx.Buffer )\r
859 + BufferLength,\r
860 0,\r
861 DEBUG_TX );\r
862 if ( !EFI_ERROR ( Status )) {\r
863 //\r
864 // Initialize the transmit operation\r
865 //\r
866 pTxData = &pPacket->Op.Udp6Tx;\r
867 pTxData->TxData.UdpSessionData = NULL;\r
868 pTxData->TxData.DataLength = (UINT32) BufferLength;\r
869 pTxData->TxData.FragmentCount = 1;\r
870 pTxData->TxData.FragmentTable[0].FragmentLength = (UINT32) BufferLength;\r
871 pTxData->TxData.FragmentTable[0].FragmentBuffer = &pPacket->Op.Udp6Tx.Buffer[0];\r
872\r
873 //\r
874 // Set the remote system address if necessary\r
875 //\r
876 pTxData->TxData.UdpSessionData = NULL;\r
877 if ( NULL != pAddress ) {\r
878 pRemoteAddress = (const struct sockaddr_in6 *)pAddress;\r
879 CopyMem ( &pTxData->Session.SourceAddress,\r
880 &pUdp6->ConfigData.StationAddress,\r
881 sizeof ( pTxData->Session.SourceAddress ));\r
882 pTxData->Session.SourcePort = 0;\r
883 CopyMem ( &pTxData->Session.DestinationAddress,\r
884 &pRemoteAddress->sin6_addr,\r
885 sizeof ( pTxData->Session.DestinationAddress ));\r
886 pTxData->Session.DestinationPort = SwapBytes16 ( pRemoteAddress->sin6_port );\r
887\r
888 //\r
889 // Use the remote system address when sending this packet\r
890 //\r
891 pTxData->TxData.UdpSessionData = &pTxData->Session;\r
892 }\r
893\r
894 //\r
895 // Copy the data into the buffer\r
896 //\r
897 CopyMem ( &pPacket->Op.Udp6Tx.Buffer[0],\r
898 pBuffer,\r
899 BufferLength );\r
900\r
901 //\r
902 // Synchronize with the socket layer\r
903 //\r
904 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
905\r
906 //\r
907 // Stop transmission after an error\r
908 //\r
909 if ( !EFI_ERROR ( pSocket->TxError )) {\r
910 //\r
911 // Display the request\r
912 //\r
913 DEBUG (( DEBUG_TX,\r
914 "Send %d %s bytes from 0x%08x\r\n",\r
915 BufferLength,\r
916 pBuffer ));\r
917\r
918 //\r
919 // Queue the data for transmission\r
920 //\r
921 pPacket->pNext = NULL;\r
922 pPreviousPacket = pSocket->pTxPacketListTail;\r
923 if ( NULL == pPreviousPacket ) {\r
924 pSocket->pTxPacketListHead = pPacket;\r
925 }\r
926 else {\r
927 pPreviousPacket->pNext = pPacket;\r
928 }\r
929 pSocket->pTxPacketListTail = pPacket;\r
930 DEBUG (( DEBUG_TX,\r
931 "0x%08x: Packet on transmit list\r\n",\r
932 pPacket ));\r
933\r
934 //\r
935 // Account for the buffered data\r
936 //\r
937 *pTxBytes += BufferLength;\r
938 *pDataLength = BufferLength;\r
939\r
940 //\r
941 // Start the transmit engine if it is idle\r
942 //\r
943 if ( NULL != pPort->pTxFree ) {\r
944 EslSocketTxStart ( pPort,\r
945 &pSocket->pTxPacketListHead,\r
946 &pSocket->pTxPacketListTail,\r
947 &pPort->pTxActive,\r
948 &pPort->pTxFree );\r
949 }\r
950 }\r
951 else {\r
952 //\r
953 // Previous transmit error\r
954 // Stop transmission\r
955 //\r
956 Status = pSocket->TxError;\r
957 pSocket->errno = EIO;\r
958\r
959 //\r
960 // Free the packet\r
961 //\r
962 EslSocketPacketFree ( pPacket, DEBUG_TX );\r
884ed923 963 break;\r
3bdf9aae 964 }\r
965\r
966 //\r
967 // Release the socket layer synchronization\r
968 //\r
969 RESTORE_TPL ( TplPrevious );\r
970 }\r
971 else {\r
972 //\r
973 // Packet allocation failed\r
974 //\r
975 pSocket->errno = ENOMEM;\r
884ed923 976 break;\r
3bdf9aae 977 }\r
884ed923 978\r
3bdf9aae 979 //\r
884ed923 980 // Set the next port\r
3bdf9aae 981 //\r
884ed923 982 pPort = pPort->pLinkSocket;\r
3bdf9aae 983 }\r
984 }\r
884ed923 985 else {\r
986 //\r
987 // Not enough buffer space available\r
988 //\r
989 pSocket->errno = EAGAIN;\r
990 Status = EFI_NOT_READY;\r
991 }\r
3bdf9aae 992 }\r
993\r
994 //\r
995 // Return the operation status\r
996 //\r
997 DBG_EXIT_STATUS ( Status );\r
998 return Status;\r
999}\r
1000\r
1001\r
1002/**\r
1003 Process the transmit completion\r
1004\r
1005 This routine use ::EslSocketTxComplete to perform the transmit\r
1006 completion processing for data packets.\r
1007\r
1008 This routine is called by the UDPv4 network layer when a data\r
1009 transmit request completes.\r
1010\r
1011 @param [in] Event The normal transmit completion event\r
1012\r
1013 @param [in] pIo Address of an ::ESL_IO_MGMT structure\r
1014\r
1015**/\r
1016VOID\r
1017EslUdp6TxComplete (\r
1018 IN EFI_EVENT Event,\r
1019 IN ESL_IO_MGMT * pIo\r
1020 )\r
1021{\r
1022 UINT32 LengthInBytes;\r
1023 ESL_PORT * pPort;\r
1024 ESL_PACKET * pPacket;\r
1025 ESL_SOCKET * pSocket;\r
1026 EFI_STATUS Status;\r
1027 \r
1028 DBG_ENTER ( );\r
1029 \r
1030 //\r
1031 // Locate the active transmit packet\r
1032 //\r
1033 pPacket = pIo->pPacket;\r
1034 pPort = pIo->pPort;\r
1035 pSocket = pPort->pSocket;\r
1036\r
1037 //\r
1038 // Get the transmit length and status\r
1039 //\r
1040 LengthInBytes = pPacket->Op.Udp6Tx.TxData.DataLength;\r
1041 pSocket->TxBytes -= LengthInBytes;\r
1042 Status = pIo->Token.Udp6Tx.Status;\r
1043\r
1044 //\r
1045 // Complete the transmit operation\r
1046 //\r
1047 EslSocketTxComplete ( pIo,\r
1048 LengthInBytes,\r
1049 Status,\r
1050 "UDP ",\r
1051 &pSocket->pTxPacketListHead,\r
1052 &pSocket->pTxPacketListTail,\r
1053 &pPort->pTxActive,\r
1054 &pPort->pTxFree );\r
1055 DBG_EXIT ( );\r
1056}\r
1057\r
1058\r
1059/**\r
1060 Interface between the socket layer and the network specific\r
1061 code that supports SOCK_DGRAM sockets over UDPv4.\r
1062**/\r
1063CONST ESL_PROTOCOL_API cEslUdp6Api = {\r
1064 "UDPv6",\r
1065 IPPROTO_UDP,\r
1066 OFFSET_OF ( ESL_PORT, Context.Udp6.ConfigData ),\r
1067 OFFSET_OF ( ESL_LAYER, pUdp6List ),\r
1068 sizeof ( struct sockaddr_in6 ),\r
1069 sizeof ( struct sockaddr_in6 ),\r
1070 AF_INET6,\r
1071 sizeof (((ESL_PACKET *)0 )->Op.Udp6Rx ),\r
1072 sizeof (((ESL_PACKET *)0 )->Op.Udp6Rx ),\r
1073 OFFSET_OF ( ESL_IO_MGMT, Token.Udp6Rx.Packet.RxData ),\r
1074 FALSE,\r
1075 EADDRINUSE,\r
1076 NULL, // Accept\r
1077 NULL, // ConnectPoll\r
1078 NULL, // ConnectStart\r
1079 EslUdp6SocketIsConfigured,\r
1080 EslUdp6LocalAddressGet,\r
1081 EslUdp6LocalAddressSet,\r
1082 NULL, // Listen\r
1083 NULL, // OptionGet\r
1084 NULL, // OptionSet\r
1085 EslUdp6PacketFree,\r
1086 EslUdp6PortAllocate,\r
1087 NULL, // PortClose,\r
1088 NULL, // PortCloseOp\r
1089 TRUE,\r
1090 EslUdp6Receive,\r
1091 EslUdp6RemoteAddressGet,\r
1092 EslUdp6RemoteAddressSet,\r
1093 EslUdp6RxComplete,\r
1094 NULL, // RxStart\r
1095 EslUdp6TxBuffer,\r
1096 EslUdp6TxComplete,\r
1097 NULL // TxOobComplete\r
1098};\r