2 Berkeley Packet Filter implementation of the EMU_SNP_PROTOCOL that allows the
3 emulator to get on real networks.
7 Copyright (c) 2004 - 2019, Intel Corporation. All rights reserved.<BR>
8 Portions copyright (c) 2011, Apple Inc. All rights reserved.
10 SPDX-License-Identifier: BSD-2-Clause-Patent
18 #include <Library/NetLib.h>
20 #define EMU_SNP_PRIVATE_SIGNATURE SIGNATURE_32('E', 'M', 's', 'n')
24 EMU_IO_THUNK_PROTOCOL
*Thunk
;
25 EMU_SNP_PROTOCOL EmuSnp
;
26 EFI_SIMPLE_NETWORK_MODE
*Mode
;
30 EFI_MAC_ADDRESS MacAddress
;
35 // Two walking pointers to manage the multiple packets that can be returned
38 VOID
*CurrentReadPointer
;
41 UINT32 ReceivedPackets
;
42 UINT32 DroppedPackets
;
45 #define EMU_SNP_PRIVATE_DATA_FROM_THIS(a) \
46 CR(a, EMU_SNP_PRIVATE, EmuSnp, EMU_SNP_PRIVATE_SIGNATURE)
49 // Strange, but there doesn't appear to be any structure for the Ethernet header in edk2...
53 UINT8 DstAddr
[NET_ETHER_ADDR_LEN
];
54 UINT8 SrcAddr
[NET_ETHER_ADDR_LEN
];
59 Register storage for SNP Mode.
61 @param This Protocol instance pointer.
62 @param Mode SimpleNetworkProtocol Mode structure passed into driver.
64 @retval EFI_SUCCESS The network interface was started.
65 @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
70 IN EMU_SNP_PROTOCOL
*This
,
71 IN EFI_SIMPLE_NETWORK_MODE
*Mode
74 EMU_SNP_PRIVATE
*Private
;
76 Private
= EMU_SNP_PRIVATE_DATA_FROM_THIS (This
);
81 // Set the broadcast address.
83 SetMem (&Mode
->BroadcastAddress
, sizeof (EFI_MAC_ADDRESS
), 0xFF);
85 CopyMem (&Mode
->CurrentAddress
, &Private
->MacAddress
, sizeof (EFI_MAC_ADDRESS
));
86 CopyMem (&Mode
->PermanentAddress
, &Private
->MacAddress
, sizeof (EFI_MAC_ADDRESS
));
89 // Since the fake SNP is based on a real NIC, to avoid conflict with the host NIC
90 // network stack, we use a different MAC address.
91 // So just change the last byte of the MAC address for the real NIC.
93 Mode
->CurrentAddress
.Addr
[NET_ETHER_ADDR_LEN
- 1]++;
98 static struct bpf_insn mFilterInstructionTemplate
[] = {
99 // Load 4 bytes from the destination MAC address.
100 BPF_STMT (BPF_LD
+ BPF_W
+ BPF_ABS
, OFFSET_OF (ETHERNET_HEADER
, DstAddr
[0])),
102 // Compare to first 4 bytes of fake MAC address.
103 BPF_JUMP (BPF_JMP
+ BPF_JEQ
+ BPF_K
, 0x12345678, 0, 3),
105 // Load remaining 2 bytes from the destination MAC address.
106 BPF_STMT (BPF_LD
+ BPF_H
+ BPF_ABS
, OFFSET_OF (ETHERNET_HEADER
, DstAddr
[4])),
108 // Compare to remaining 2 bytes of fake MAC address.
109 BPF_JUMP (BPF_JMP
+ BPF_JEQ
+ BPF_K
, 0x9ABC, 5, 0),
111 // Load 4 bytes from the destination MAC address.
112 BPF_STMT (BPF_LD
+ BPF_W
+ BPF_ABS
, OFFSET_OF (ETHERNET_HEADER
, DstAddr
[0])),
114 // Compare to first 4 bytes of broadcast MAC address.
115 BPF_JUMP (BPF_JMP
+ BPF_JEQ
+ BPF_K
, 0xFFFFFFFF, 0, 2),
117 // Load remaining 2 bytes from the destination MAC address.
118 BPF_STMT (BPF_LD
+ BPF_H
+ BPF_ABS
, OFFSET_OF (ETHERNET_HEADER
, DstAddr
[4])),
120 // Compare to remaining 2 bytes of broadcast MAC address.
121 BPF_JUMP (BPF_JMP
+ BPF_JEQ
+ BPF_K
, 0xFFFF, 1, 0),
124 BPF_STMT (BPF_RET
+ BPF_K
, 0),
126 // Receive entire packet.
127 BPF_STMT (BPF_RET
+ BPF_K
, -1)
131 OpenBpfFileDescriptor (
132 IN EMU_SNP_PRIVATE
*Private
,
136 char BfpDeviceName
[256];
140 // Open a Berkeley Packet Filter device. This must be done as root, so this is probably
141 // the place which is most likely to fail...
143 for (Index
= 0; TRUE
; Index
++ ) {
144 snprintf (BfpDeviceName
, sizeof (BfpDeviceName
), "/dev/bpf%d", Index
);
146 *Fd
= open (BfpDeviceName
, O_RDWR
, 0);
151 if (errno
== EACCES
) {
153 "SNP: Permissions on '%s' are incorrect. Fix with 'sudo chmod 666 %s'.\n",
159 if (errno
!= EBUSY
) {
164 return EFI_OUT_OF_RESOURCES
;
168 Changes the state of a network interface from "stopped" to "started".
170 @param This Protocol instance pointer.
172 @retval EFI_SUCCESS The network interface was started.
173 @retval EFI_ALREADY_STARTED The network interface is already in the started state.
174 @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
175 @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
176 @retval EFI_UNSUPPORTED This function is not supported by the network interface.
181 IN EMU_SNP_PROTOCOL
*This
185 EMU_SNP_PRIVATE
*Private
;
186 struct ifreq BoundIf
;
187 struct bpf_program BpfProgram
;
188 struct bpf_insn
*FilterProgram
;
190 u_int ReadBufferSize
;
194 Private
= EMU_SNP_PRIVATE_DATA_FROM_THIS (This
);
196 switch (Private
->Mode
->State
) {
197 case EfiSimpleNetworkStopped
:
200 case EfiSimpleNetworkStarted
:
201 case EfiSimpleNetworkInitialized
:
202 return EFI_ALREADY_STARTED
;
206 return EFI_DEVICE_ERROR
;
210 Status
= EFI_SUCCESS
;
211 Private
->ReadBuffer
= NULL
;
212 if (Private
->BpfFd
== 0) {
213 Status
= OpenBpfFileDescriptor (Private
, &Private
->BpfFd
);
214 if (EFI_ERROR (Status
)) {
215 goto DeviceErrorExit
;
219 // Get the read buffer size.
221 if (ioctl (Private
->BpfFd
, BIOCGBLEN
, &ReadBufferSize
) < 0) {
222 goto DeviceErrorExit
;
226 // Default value from BIOCGBLEN is usually too small, so use a much larger size, if necessary.
228 if (ReadBufferSize
< FixedPcdGet32 (PcdNetworkPacketFilterSize
)) {
229 ReadBufferSize
= FixedPcdGet32 (PcdNetworkPacketFilterSize
);
230 if (ioctl (Private
->BpfFd
, BIOCSBLEN
, &ReadBufferSize
) < 0) {
231 goto DeviceErrorExit
;
236 // Associate our interface with this BPF file descriptor.
238 AsciiStrCpyS (BoundIf
.ifr_name
, sizeof (BoundIf
.ifr_name
), Private
->InterfaceName
);
239 if (ioctl (Private
->BpfFd
, BIOCSETIF
, &BoundIf
) < 0) {
240 goto DeviceErrorExit
;
244 // Enable immediate mode.
247 if (ioctl (Private
->BpfFd
, BIOCIMMEDIATE
, &Value
) < 0) {
248 goto DeviceErrorExit
;
252 // Enable non-blocking I/O.
254 if (fcntl (Private
->BpfFd
, F_GETFL
, 0) == -1) {
255 goto DeviceErrorExit
;
260 if (fcntl (Private
->BpfFd
, F_SETFL
, Value
) == -1) {
261 goto DeviceErrorExit
;
265 // Disable "header complete" flag. This means the supplied source MAC address is
266 // what goes on the wire.
269 if (ioctl (Private
->BpfFd
, BIOCSHDRCMPLT
, &Value
) < 0) {
270 goto DeviceErrorExit
;
274 // Allocate read buffer.
276 Private
->ReadBufferSize
= ReadBufferSize
;
277 Private
->ReadBuffer
= malloc (Private
->ReadBufferSize
);
278 if (Private
->ReadBuffer
== NULL
) {
282 Private
->CurrentReadPointer
= Private
->EndReadPointer
= Private
->ReadBuffer
;
285 // Install our packet filter: successful reads should only produce broadcast or unicast
286 // packets directed to our fake MAC address.
288 FilterProgram
= malloc (sizeof (mFilterInstructionTemplate
));
289 if ( FilterProgram
== NULL
) {
293 CopyMem (FilterProgram
, &mFilterInstructionTemplate
, sizeof (mFilterInstructionTemplate
));
296 // Insert out fake MAC address into the filter. The data has to be host endian.
298 CopyMem (&Temp32
, &Private
->Mode
->CurrentAddress
.Addr
[0], sizeof (UINT32
));
299 FilterProgram
[1].k
= NTOHL (Temp32
);
300 CopyMem (&Temp16
, &Private
->Mode
->CurrentAddress
.Addr
[4], sizeof (UINT16
));
301 FilterProgram
[3].k
= NTOHS (Temp16
);
303 BpfProgram
.bf_len
= sizeof (mFilterInstructionTemplate
) / sizeof (struct bpf_insn
);
304 BpfProgram
.bf_insns
= FilterProgram
;
306 if (ioctl (Private
->BpfFd
, BIOCSETF
, &BpfProgram
) < 0) {
307 goto DeviceErrorExit
;
310 free (FilterProgram
);
313 // Enable promiscuous mode.
315 if (ioctl (Private
->BpfFd
, BIOCPROMISC
, 0) < 0) {
316 goto DeviceErrorExit
;
319 Private
->Mode
->State
= EfiSimpleNetworkStarted
;
325 Status
= EFI_DEVICE_ERROR
;
327 if (Private
->ReadBuffer
!= NULL
) {
328 free (Private
->ReadBuffer
);
329 Private
->ReadBuffer
= NULL
;
336 Changes the state of a network interface from "started" to "stopped".
338 @param This Protocol instance pointer.
340 @retval EFI_SUCCESS The network interface was stopped.
341 @retval EFI_ALREADY_STARTED The network interface is already in the stopped state.
342 @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
343 @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
344 @retval EFI_UNSUPPORTED This function is not supported by the network interface.
349 IN EMU_SNP_PROTOCOL
*This
352 EMU_SNP_PRIVATE
*Private
;
354 Private
= EMU_SNP_PRIVATE_DATA_FROM_THIS (This
);
356 switch ( Private
->Mode
->State
) {
357 case EfiSimpleNetworkStarted
:
360 case EfiSimpleNetworkStopped
:
361 return EFI_NOT_STARTED
;
365 return EFI_DEVICE_ERROR
;
369 if (Private
->BpfFd
!= 0) {
370 close (Private
->BpfFd
);
374 if (Private
->ReadBuffer
!= NULL
) {
375 free (Private
->ReadBuffer
);
376 Private
->CurrentReadPointer
= Private
->EndReadPointer
= Private
->ReadBuffer
= NULL
;
379 Private
->Mode
->State
= EfiSimpleNetworkStopped
;
385 Resets a network adapter and allocates the transmit and receive buffers
386 required by the network interface; optionally, also requests allocation
387 of additional transmit and receive buffers.
389 @param This The protocol instance pointer.
390 @param ExtraRxBufferSize The size, in bytes, of the extra receive buffer space
391 that the driver should allocate for the network interface.
392 Some network interfaces will not be able to use the extra
393 buffer, and the caller will not know if it is actually
395 @param ExtraTxBufferSize The size, in bytes, of the extra transmit buffer space
396 that the driver should allocate for the network interface.
397 Some network interfaces will not be able to use the extra
398 buffer, and the caller will not know if it is actually
401 @retval EFI_SUCCESS The network interface was initialized.
402 @retval EFI_NOT_STARTED The network interface has not been started.
403 @retval EFI_OUT_OF_RESOURCES There was not enough memory for the transmit and
405 @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
406 @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
407 @retval EFI_UNSUPPORTED This function is not supported by the network interface.
412 IN EMU_SNP_PROTOCOL
*This
,
413 IN UINTN ExtraRxBufferSize OPTIONAL
,
414 IN UINTN ExtraTxBufferSize OPTIONAL
417 EMU_SNP_PRIVATE
*Private
;
419 Private
= EMU_SNP_PRIVATE_DATA_FROM_THIS (This
);
421 switch ( Private
->Mode
->State
) {
422 case EfiSimpleNetworkStarted
:
425 case EfiSimpleNetworkStopped
:
426 return EFI_NOT_STARTED
;
430 return EFI_DEVICE_ERROR
;
434 Private
->Mode
->MCastFilterCount
= 0;
435 Private
->Mode
->ReceiveFilterSetting
= 0;
436 ZeroMem (Private
->Mode
->MCastFilter
, sizeof (Private
->Mode
->MCastFilter
));
438 Private
->Mode
->State
= EfiSimpleNetworkInitialized
;
444 Resets a network adapter and re-initializes it with the parameters that were
445 provided in the previous call to Initialize().
447 @param This The protocol instance pointer.
448 @param ExtendedVerification Indicates that the driver may perform a more
449 exhaustive verification operation of the device
452 @retval EFI_SUCCESS The network interface was reset.
453 @retval EFI_NOT_STARTED The network interface has not been started.
454 @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
455 @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
456 @retval EFI_UNSUPPORTED This function is not supported by the network interface.
461 IN EMU_SNP_PROTOCOL
*This
,
462 IN BOOLEAN ExtendedVerification
465 EMU_SNP_PRIVATE
*Private
;
467 Private
= EMU_SNP_PRIVATE_DATA_FROM_THIS (This
);
469 switch ( Private
->Mode
->State
) {
470 case EfiSimpleNetworkInitialized
:
473 case EfiSimpleNetworkStopped
:
474 return EFI_NOT_STARTED
;
478 return EFI_DEVICE_ERROR
;
486 Resets a network adapter and leaves it in a state that is safe for
487 another driver to initialize.
489 @param This Protocol instance pointer.
491 @retval EFI_SUCCESS The network interface was shutdown.
492 @retval EFI_NOT_STARTED The network interface has not been started.
493 @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
494 @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
495 @retval EFI_UNSUPPORTED This function is not supported by the network interface.
500 IN EMU_SNP_PROTOCOL
*This
503 EMU_SNP_PRIVATE
*Private
;
505 Private
= EMU_SNP_PRIVATE_DATA_FROM_THIS (This
);
507 switch ( Private
->Mode
->State
) {
508 case EfiSimpleNetworkInitialized
:
511 case EfiSimpleNetworkStopped
:
512 return EFI_NOT_STARTED
;
516 return EFI_DEVICE_ERROR
;
520 Private
->Mode
->State
= EfiSimpleNetworkStarted
;
522 Private
->Mode
->ReceiveFilterSetting
= 0;
523 Private
->Mode
->MCastFilterCount
= 0;
524 ZeroMem (Private
->Mode
->MCastFilter
, sizeof (Private
->Mode
->MCastFilter
));
526 if (Private
->BpfFd
!= 0) {
527 close (Private
->BpfFd
);
531 if (Private
->ReadBuffer
!= NULL
) {
532 free (Private
->ReadBuffer
);
533 Private
->CurrentReadPointer
= Private
->EndReadPointer
= Private
->ReadBuffer
= NULL
;
540 Manages the multicast receive filters of a network interface.
542 @param This The protocol instance pointer.
543 @param Enable A bit mask of receive filters to enable on the network interface.
544 @param Disable A bit mask of receive filters to disable on the network interface.
545 @param ResetMCastFilter Set to TRUE to reset the contents of the multicast receive
546 filters on the network interface to their default values.
547 @param McastFilterCnt Number of multicast HW MAC addresses in the new
548 MCastFilter list. This value must be less than or equal to
549 the MCastFilterCnt field of EMU_SNP_MODE. This
550 field is optional if ResetMCastFilter is TRUE.
551 @param MCastFilter A pointer to a list of new multicast receive filter HW MAC
552 addresses. This list will replace any existing multicast
553 HW MAC address list. This field is optional if
554 ResetMCastFilter is TRUE.
556 @retval EFI_SUCCESS The multicast receive filter list was updated.
557 @retval EFI_NOT_STARTED The network interface has not been started.
558 @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
559 @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
560 @retval EFI_UNSUPPORTED This function is not supported by the network interface.
564 EmuSnpReceiveFilters (
565 IN EMU_SNP_PROTOCOL
*This
,
568 IN BOOLEAN ResetMCastFilter
,
569 IN UINTN MCastFilterCnt OPTIONAL
,
570 IN EFI_MAC_ADDRESS
*MCastFilter OPTIONAL
573 EMU_SNP_PRIVATE
*Private
;
575 Private
= EMU_SNP_PRIVATE_DATA_FROM_THIS (This
);
577 // For now, just succeed...
582 Modifies or resets the current station address, if supported.
584 @param This The protocol instance pointer.
585 @param Reset Flag used to reset the station address to the network interfaces
587 @param New The new station address to be used for the network interface.
589 @retval EFI_SUCCESS The network interfaces station address was updated.
590 @retval EFI_NOT_STARTED The network interface has not been started.
591 @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
592 @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
593 @retval EFI_UNSUPPORTED This function is not supported by the network interface.
597 EmuSnpStationAddress (
598 IN EMU_SNP_PROTOCOL
*This
,
600 IN EFI_MAC_ADDRESS
*New OPTIONAL
603 EMU_SNP_PRIVATE
*Private
;
605 Private
= EMU_SNP_PRIVATE_DATA_FROM_THIS (This
);
607 return EFI_UNSUPPORTED
;
611 Resets or collects the statistics on a network interface.
613 @param This Protocol instance pointer.
614 @param Reset Set to TRUE to reset the statistics for the network interface.
615 @param StatisticsSize On input the size, in bytes, of StatisticsTable. On
616 output the size, in bytes, of the resulting table of
618 @param StatisticsTable A pointer to the EFI_NETWORK_STATISTICS structure that
619 contains the statistics.
621 @retval EFI_SUCCESS The statistics were collected from the network interface.
622 @retval EFI_NOT_STARTED The network interface has not been started.
623 @retval EFI_BUFFER_TOO_SMALL The Statistics buffer was too small. The current buffer
624 size needed to hold the statistics is returned in
626 @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
627 @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
628 @retval EFI_UNSUPPORTED This function is not supported by the network interface.
633 IN EMU_SNP_PROTOCOL
*This
,
635 IN OUT UINTN
*StatisticsSize OPTIONAL
,
636 OUT EFI_NETWORK_STATISTICS
*StatisticsTable OPTIONAL
639 EMU_SNP_PRIVATE
*Private
;
641 Private
= EMU_SNP_PRIVATE_DATA_FROM_THIS (This
);
643 return EFI_UNSUPPORTED
;
647 Converts a multicast IP address to a multicast HW MAC address.
649 @param This The protocol instance pointer.
650 @param IPv6 Set to TRUE if the multicast IP address is IPv6 [RFC 2460]. Set
651 to FALSE if the multicast IP address is IPv4 [RFC 791].
652 @param IP The multicast IP address that is to be converted to a multicast
654 @param MAC The multicast HW MAC address that is to be generated from IP.
656 @retval EFI_SUCCESS The multicast IP address was mapped to the multicast
658 @retval EFI_NOT_STARTED The network interface has not been started.
659 @retval EFI_BUFFER_TOO_SMALL The Statistics buffer was too small. The current buffer
660 size needed to hold the statistics is returned in
662 @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
663 @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
664 @retval EFI_UNSUPPORTED This function is not supported by the network interface.
669 IN EMU_SNP_PROTOCOL
*This
,
671 IN EFI_IP_ADDRESS
*IP
,
672 OUT EFI_MAC_ADDRESS
*MAC
675 EMU_SNP_PRIVATE
*Private
;
677 Private
= EMU_SNP_PRIVATE_DATA_FROM_THIS (This
);
679 return EFI_UNSUPPORTED
;
683 Performs read and write operations on the NVRAM device attached to a
686 @param This The protocol instance pointer.
687 @param ReadWrite TRUE for read operations, FALSE for write operations.
688 @param Offset Byte offset in the NVRAM device at which to start the read or
689 write operation. This must be a multiple of NvRamAccessSize and
691 @param BufferSize The number of bytes to read or write from the NVRAM device.
692 This must also be a multiple of NvramAccessSize.
693 @param Buffer A pointer to the data buffer.
695 @retval EFI_SUCCESS The NVRAM access was performed.
696 @retval EFI_NOT_STARTED The network interface has not been started.
697 @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
698 @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
699 @retval EFI_UNSUPPORTED This function is not supported by the network interface.
704 IN EMU_SNP_PROTOCOL
*This
,
705 IN BOOLEAN ReadWrite
,
711 EMU_SNP_PRIVATE
*Private
;
713 Private
= EMU_SNP_PRIVATE_DATA_FROM_THIS (This
);
715 return EFI_UNSUPPORTED
;
719 Reads the current interrupt status and recycled transmit buffer status from
722 @param This The protocol instance pointer.
723 @param InterruptStatus A pointer to the bit mask of the currently active interrupts
724 If this is NULL, the interrupt status will not be read from
725 the device. If this is not NULL, the interrupt status will
726 be read from the device. When the interrupt status is read,
727 it will also be cleared. Clearing the transmit interrupt
728 does not empty the recycled transmit buffer array.
729 @param TxBuf Recycled transmit buffer address. The network interface will
730 not transmit if its internal recycled transmit buffer array
731 is full. Reading the transmit buffer does not clear the
732 transmit interrupt. If this is NULL, then the transmit buffer
733 status will not be read. If there are no transmit buffers to
734 recycle and TxBuf is not NULL, * TxBuf will be set to NULL.
736 @retval EFI_SUCCESS The status of the network interface was retrieved.
737 @retval EFI_NOT_STARTED The network interface has not been started.
738 @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
739 @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
740 @retval EFI_UNSUPPORTED This function is not supported by the network interface.
745 IN EMU_SNP_PROTOCOL
*This
,
746 OUT UINT32
*InterruptStatus OPTIONAL
,
747 OUT VOID
**TxBuf OPTIONAL
750 EMU_SNP_PRIVATE
*Private
;
752 Private
= EMU_SNP_PRIVATE_DATA_FROM_THIS (This
);
754 if ( InterruptStatus
!= NULL
) {
755 *InterruptStatus
= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT
;
762 Places a packet in the transmit queue of a network interface.
764 @param This The protocol instance pointer.
765 @param HeaderSize The size, in bytes, of the media header to be filled in by
766 the Transmit() function. If HeaderSize is non-zero, then it
767 must be equal to This->Mode->MediaHeaderSize and the DestAddr
768 and Protocol parameters must not be NULL.
769 @param BufferSize The size, in bytes, of the entire packet (media header and
770 data) to be transmitted through the network interface.
771 @param Buffer A pointer to the packet (media header followed by data) to be
772 transmitted. This parameter cannot be NULL. If HeaderSize is zero,
773 then the media header in Buffer must already be filled in by the
774 caller. If HeaderSize is non-zero, then the media header will be
775 filled in by the Transmit() function.
776 @param SrcAddr The source HW MAC address. If HeaderSize is zero, then this parameter
777 is ignored. If HeaderSize is non-zero and SrcAddr is NULL, then
778 This->Mode->CurrentAddress is used for the source HW MAC address.
779 @param DestAddr The destination HW MAC address. If HeaderSize is zero, then this
780 parameter is ignored.
781 @param Protocol The type of header to build. If HeaderSize is zero, then this
782 parameter is ignored. See RFC 1700, section "Ether Types", for
785 @retval EFI_SUCCESS The packet was placed on the transmit queue.
786 @retval EFI_NOT_STARTED The network interface has not been started.
787 @retval EFI_NOT_READY The network interface is too busy to accept this transmit request.
788 @retval EFI_BUFFER_TOO_SMALL The BufferSize parameter is too small.
789 @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
790 @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
791 @retval EFI_UNSUPPORTED This function is not supported by the network interface.
796 IN EMU_SNP_PROTOCOL
*This
,
800 IN EFI_MAC_ADDRESS
*SrcAddr OPTIONAL
,
801 IN EFI_MAC_ADDRESS
*DestAddr OPTIONAL
,
802 IN UINT16
*Protocol OPTIONAL
805 EMU_SNP_PRIVATE
*Private
;
806 ETHERNET_HEADER
*EnetHeader
;
808 Private
= EMU_SNP_PRIVATE_DATA_FROM_THIS (This
);
810 if (Private
->Mode
->State
< EfiSimpleNetworkStarted
) {
811 return EFI_NOT_STARTED
;
814 if ( HeaderSize
!= 0 ) {
815 if ((DestAddr
== NULL
) || (Protocol
== NULL
) || (HeaderSize
!= Private
->Mode
->MediaHeaderSize
)) {
816 return EFI_INVALID_PARAMETER
;
819 if (SrcAddr
== NULL
) {
820 SrcAddr
= &Private
->Mode
->CurrentAddress
;
823 EnetHeader
= (ETHERNET_HEADER
*)Buffer
;
825 CopyMem (EnetHeader
->DstAddr
, DestAddr
, NET_ETHER_ADDR_LEN
);
826 CopyMem (EnetHeader
->SrcAddr
, SrcAddr
, NET_ETHER_ADDR_LEN
);
828 EnetHeader
->Type
= HTONS (*Protocol
);
831 if (write (Private
->BpfFd
, Buffer
, BufferSize
) < 0) {
832 return EFI_DEVICE_ERROR
;
839 Receives a packet from a network interface.
841 @param This The protocol instance pointer.
842 @param HeaderSize The size, in bytes, of the media header received on the network
843 interface. If this parameter is NULL, then the media header size
844 will not be returned.
845 @param BufferSize On entry, the size, in bytes, of Buffer. On exit, the size, in
846 bytes, of the packet that was received on the network interface.
847 @param Buffer A pointer to the data buffer to receive both the media header and
849 @param SrcAddr The source HW MAC address. If this parameter is NULL, the
850 HW MAC source address will not be extracted from the media
852 @param DestAddr The destination HW MAC address. If this parameter is NULL,
853 the HW MAC destination address will not be extracted from the
855 @param Protocol The media header type. If this parameter is NULL, then the
856 protocol will not be extracted from the media header. See
857 RFC 1700 section "Ether Types" for examples.
859 @retval EFI_SUCCESS The received data was stored in Buffer, and BufferSize has
860 been updated to the number of bytes received.
861 @retval EFI_NOT_STARTED The network interface has not been started.
862 @retval EFI_NOT_READY The network interface is too busy to accept this transmit
864 @retval EFI_BUFFER_TOO_SMALL The BufferSize parameter is too small.
865 @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
866 @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
867 @retval EFI_UNSUPPORTED This function is not supported by the network interface.
872 IN EMU_SNP_PROTOCOL
*This
,
873 OUT UINTN
*HeaderSize OPTIONAL
,
874 IN OUT UINTN
*BufferSize
,
876 OUT EFI_MAC_ADDRESS
*SrcAddr OPTIONAL
,
877 OUT EFI_MAC_ADDRESS
*DestAddr OPTIONAL
,
878 OUT UINT16
*Protocol OPTIONAL
881 EMU_SNP_PRIVATE
*Private
;
882 struct bpf_hdr
*BpfHeader
;
883 struct bpf_stat BpfStats
;
884 ETHERNET_HEADER
*EnetHeader
;
887 Private
= EMU_SNP_PRIVATE_DATA_FROM_THIS (This
);
889 if (Private
->Mode
->State
< EfiSimpleNetworkStarted
) {
890 return EFI_NOT_STARTED
;
893 ZeroMem (&BpfStats
, sizeof (BpfStats
));
895 if (ioctl (Private
->BpfFd
, BIOCGSTATS
, &BpfStats
) == 0) {
896 Private
->ReceivedPackets
+= BpfStats
.bs_recv
;
897 if (BpfStats
.bs_drop
> Private
->DroppedPackets
) {
899 "SNP: STATS: RCVD = %d DROPPED = %d. Probably need to increase BPF PcdNetworkPacketFilterSize?\n",
901 BpfStats
.bs_drop
- Private
->DroppedPackets
903 Private
->DroppedPackets
= BpfStats
.bs_drop
;
908 // Do we have any remaining packets from the previous read?
910 if (Private
->CurrentReadPointer
>= Private
->EndReadPointer
) {
911 Result
= read (Private
->BpfFd
, Private
->ReadBuffer
, Private
->ReadBufferSize
);
913 // EAGAIN means that there's no I/O outstanding against this file descriptor.
914 return (errno
== EAGAIN
) ? EFI_NOT_READY
: EFI_DEVICE_ERROR
;
918 return EFI_NOT_READY
;
921 Private
->CurrentReadPointer
= Private
->ReadBuffer
;
922 Private
->EndReadPointer
= Private
->CurrentReadPointer
+ Result
;
925 BpfHeader
= Private
->CurrentReadPointer
;
926 EnetHeader
= Private
->CurrentReadPointer
+ BpfHeader
->bh_hdrlen
;
928 if (BpfHeader
->bh_caplen
> *BufferSize
) {
929 *BufferSize
= BpfHeader
->bh_caplen
;
930 return EFI_BUFFER_TOO_SMALL
;
933 CopyMem (Buffer
, EnetHeader
, BpfHeader
->bh_caplen
);
934 *BufferSize
= BpfHeader
->bh_caplen
;
936 if (HeaderSize
!= NULL
) {
937 *HeaderSize
= sizeof (ETHERNET_HEADER
);
940 if (DestAddr
!= NULL
) {
941 ZeroMem (DestAddr
, sizeof (EFI_MAC_ADDRESS
));
942 CopyMem (DestAddr
, EnetHeader
->DstAddr
, NET_ETHER_ADDR_LEN
);
945 if (SrcAddr
!= NULL
) {
946 ZeroMem (SrcAddr
, sizeof (EFI_MAC_ADDRESS
));
947 CopyMem (SrcAddr
, EnetHeader
->SrcAddr
, NET_ETHER_ADDR_LEN
);
950 if (Protocol
!= NULL
) {
951 *Protocol
= NTOHS (EnetHeader
->Type
);
954 Private
->CurrentReadPointer
+= BPF_WORDALIGN (BpfHeader
->bh_hdrlen
+ BpfHeader
->bh_caplen
);
958 EMU_SNP_PROTOCOL gEmuSnpProtocol
= {
959 GasketSnpCreateMapping
,
965 GasketSnpReceiveFilters
,
966 GasketSnpStationAddress
,
968 GasketSnpMCastIpToMac
,
976 GetInterfaceMacAddr (
977 EMU_SNP_PRIVATE
*Private
981 struct ifaddrs
*IfAddrs
;
983 struct sockaddr_dl
*IfSdl
;
985 if (getifaddrs (&IfAddrs
) != 0) {
986 return EFI_UNSUPPORTED
;
990 // Convert the interface name to ASCII so we can find it.
992 Private
->InterfaceName
= malloc (StrSize (Private
->Thunk
->ConfigString
));
993 if (Private
->InterfaceName
== NULL
) {
994 Status
= EFI_OUT_OF_RESOURCES
;
998 UnicodeStrToAsciiStrS (
999 Private
->Thunk
->ConfigString
,
1000 Private
->InterfaceName
,
1001 StrSize (Private
->Thunk
->ConfigString
)
1004 Status
= EFI_NOT_FOUND
;
1006 while (If
!= NULL
) {
1007 IfSdl
= (struct sockaddr_dl
*)If
->ifa_addr
;
1009 if (IfSdl
->sdl_family
== AF_LINK
) {
1010 if (!AsciiStrCmp (Private
->InterfaceName
, If
->ifa_name
)) {
1011 CopyMem (&Private
->MacAddress
, LLADDR (IfSdl
), NET_ETHER_ADDR_LEN
);
1013 Status
= EFI_SUCCESS
;
1022 freeifaddrs (IfAddrs
);
1028 IN EMU_IO_THUNK_PROTOCOL
*This
1031 EMU_SNP_PRIVATE
*Private
;
1033 if (This
->Private
!= NULL
) {
1034 return EFI_ALREADY_STARTED
;
1037 if (!CompareGuid (This
->Protocol
, &gEmuSnpProtocolGuid
)) {
1038 return EFI_UNSUPPORTED
;
1041 Private
= malloc (sizeof (EMU_SNP_PRIVATE
));
1042 if (Private
== NULL
) {
1043 return EFI_OUT_OF_RESOURCES
;
1046 Private
->Signature
= EMU_SNP_PRIVATE_SIGNATURE
;
1047 Private
->Thunk
= This
;
1048 CopyMem (&Private
->EmuSnp
, &gEmuSnpProtocol
, sizeof (gEmuSnpProtocol
));
1049 GetInterfaceMacAddr (Private
);
1051 This
->Interface
= &Private
->EmuSnp
;
1052 This
->Private
= Private
;
1058 IN EMU_IO_THUNK_PROTOCOL
*This
1061 EMU_SNP_PRIVATE
*Private
;
1063 if (!CompareGuid (This
->Protocol
, &gEmuSnpProtocolGuid
)) {
1064 return EFI_UNSUPPORTED
;
1067 Private
= This
->Private
;
1073 EMU_IO_THUNK_PROTOCOL gSnpThunkIo
= {
1074 &gEmuSnpProtocolGuid
,
1079 GasketSnpThunkClose
,