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