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