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