123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765 |
- /*++
- Copyright (c) 2013 Minoca Corp.
- This file is licensed under the terms of the GNU General Public License
- version 3. Alternative licensing terms are available. Contact
- info@minocacorp.com for details. See the LICENSE file at the root of this
- project for complete licensing information.
- Module Name:
- ethernet.c
- Abstract:
- This module implements functionality for Ethernet-based links.
- Author:
- Evan Green 5-Apr-2013
- Environment:
- Kernel
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- //
- // Data link layer drivers are supposed to be able to stand on their own (ie be
- // able to be implemented outside the core net library). For the builtin ones,
- // avoid including netcore.h, but still redefine those functions that would
- // otherwise generate imports.
- //
- #define NET_API __DLLEXPORT
- #include <minoca/kernel/driver.h>
- #include <minoca/net/netdrv.h>
- #include <minoca/kernel/acpi.h>
- #include <minoca/fw/smbios.h>
- #include "ethernet.h"
- //
- // ---------------------------------------------------------------- Definitions
- //
- #define ETHERNET_ALLOCATION_TAG 0x72687445 // 'rhtE'
- //
- // Printed strings of ethernet addresses look something like:
- // "12:34:56:78:9A:BC". Include the null terminator.
- //
- #define ETHERNET_STRING_LENGTH 18
- //
- // Define the Ethernet debug flags.
- //
- #define ETHERNET_DEBUG_FLAG_DROPPED_PACKETS 0x00000001
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- KSTATUS
- NetpEthernetInitializeLink (
- PNET_LINK Link
- );
- VOID
- NetpEthernetDestroyLink (
- PNET_LINK Link
- );
- KSTATUS
- NetpEthernetSend (
- PVOID DataLinkContext,
- PNET_PACKET_LIST PacketList,
- PNETWORK_ADDRESS SourcePhysicalAddress,
- PNETWORK_ADDRESS DestinationPhysicalAddress,
- ULONG ProtocolNumber
- );
- VOID
- NetpEthernetProcessReceivedPacket (
- PVOID DataLinkContext,
- PNET_PACKET_BUFFER Packet
- );
- VOID
- NetpEthernetGetBroadcastAddress (
- PNETWORK_ADDRESS PhysicalNetworkAddress
- );
- ULONG
- NetpEthernetPrintAddress (
- PNETWORK_ADDRESS Address,
- PSTR Buffer,
- ULONG BufferLength
- );
- VOID
- NetpEthernetGetPacketSizeInformation (
- PVOID DataLinkContext,
- PNET_PACKET_SIZE_INFORMATION PacketSizeInformation,
- ULONG Flags
- );
- KSTATUS
- NetpEthernetGetEthernetAddressFromSmbios (
- PULONG Address
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- //
- // Store the lower 4 bytes of the created MAC address base. This value is
- // incremented for each ethernet card that comes online without an assigned
- // ethernet address.
- //
- ULONG NetEthernetInventedAddress;
- //
- // Store a bitmask of debug flags.
- //
- ULONG EthernetDebugFlags = 0;
- //
- // ------------------------------------------------------------------ Functions
- //
- VOID
- NetpEthernetInitialize (
- VOID
- )
- /*++
- Routine Description:
- This routine initializes support for Ethernet frames.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- {
- NET_DATA_LINK_ENTRY DataLinkEntry;
- HANDLE DataLinkHandle;
- PNET_DATA_LINK_INTERFACE Interface;
- KSTATUS Status;
- DataLinkEntry.Domain = NetDomainEthernet;
- Interface = &(DataLinkEntry.Interface);
- Interface->InitializeLink = NetpEthernetInitializeLink;
- Interface->DestroyLink = NetpEthernetDestroyLink;
- Interface->Send = NetpEthernetSend;
- Interface->ProcessReceivedPacket = NetpEthernetProcessReceivedPacket;
- Interface->GetBroadcastAddress = NetpEthernetGetBroadcastAddress;
- Interface->PrintAddress = NetpEthernetPrintAddress;
- Interface->GetPacketSizeInformation = NetpEthernetGetPacketSizeInformation;
- Status = NetRegisterDataLinkLayer(&DataLinkEntry, &DataLinkHandle);
- if (!KSUCCESS(Status)) {
- ASSERT(FALSE);
- }
- return;
- }
- NET_API
- BOOL
- NetIsEthernetAddressValid (
- BYTE Address[ETHERNET_ADDRESS_SIZE]
- )
- /*++
- Routine Description:
- This routine determines if the given ethernet address is a valid individual
- address or not. This routine returns FALSE for 00:00:00:00:00:00 and
- FF:FF:FF:FF:FF:FF, and TRUE for everything else.
- Arguments:
- Address - Supplies the address to check.
- Return Value:
- TRUE if the ethernet address is a valid individual address.
- FALSE if the address is not valid.
- --*/
- {
- if ((Address[0] == 0) && (Address[1] == 0) && (Address[2] == 0) &&
- (Address[3] == 0) && (Address[4] == 0) && (Address[5] == 0)) {
- return FALSE;
- }
- if ((Address[0] == 0xFF) && (Address[1] == 0xFF) && (Address[2] == 0xFF) &&
- (Address[3] == 0xFF) && (Address[4] == 0xFF) && (Address[5] == 0xFF)) {
- return FALSE;
- }
- return TRUE;
- }
- NET_API
- VOID
- NetCreateEthernetAddress (
- BYTE Address[ETHERNET_ADDRESS_SIZE]
- )
- /*++
- Routine Description:
- This routine generates a random ethernet address.
- Arguments:
- Address - Supplies the array where the new address will be stored.
- Return Value:
- None.
- --*/
- {
- RUNLEVEL OldRunLevel;
- KSTATUS Status;
- ULONG Value;
- //
- // If no base has been assigned yet, get a random one.
- //
- if (NetEthernetInventedAddress == 0) {
- //
- // Use the SMBIOS table, which should hopefully have a platform
- // identifier in it, to compute an address that is unique to the
- // platform but remains constant across reboots. The beauty of this if
- // it works is it doesn't require any unique numbers to be stored in
- // the OS image.
- //
- Status = NetpEthernetGetEthernetAddressFromSmbios(
- &NetEthernetInventedAddress);
- if (KSUCCESS(Status)) {
- Value = NetEthernetInventedAddress;
- //
- // If there is no SMBIOS table, use the processor counter to make a
- // random address up. This unfortunately changes across reboots.
- //
- } else {
- OldRunLevel = KeRaiseRunLevel(RunLevelDispatch);
- Value = HlQueryProcessorCounter() * 12345;
- KeLowerRunLevel(OldRunLevel);
- NetEthernetInventedAddress = Value;
- }
- } else {
- Value = RtlAtomicAdd32(&NetEthernetInventedAddress, 1);
- }
- //
- // Set the first byte to 2 to indicate a locally administered unicast
- // address.
- //
- Address[0] = 0x02;
- Address[1] = 0x00;
- RtlCopyMemory(&(Address[sizeof(USHORT)]), &Value, sizeof(ULONG));
- return;
- }
- KSTATUS
- NetpEthernetInitializeLink (
- PNET_LINK Link
- )
- /*++
- Routine Description:
- This routine initializes any pieces of information needed by the data link
- layer for a new link.
- Arguments:
- Link - Supplies a pointer to the new link.
- Return Value:
- Status code.
- --*/
- {
- //
- // Ethernet does not need any extra state. It just expects to get the
- // network link passed back as the data context. No extra references on the
- // network link are taken because this data link context gets "destroyed"
- // when the network link's last reference is released.
- //
- Link->DataLinkContext = Link;
- return STATUS_SUCCESS;
- }
- VOID
- NetpEthernetDestroyLink (
- PNET_LINK Link
- )
- /*++
- Routine Description:
- This routine allows the data link layer to tear down any state before a
- link is destroyed.
- Arguments:
- Link - Supplies a pointer to the dying link.
- Return Value:
- None.
- --*/
- {
- Link->DataLinkContext = NULL;
- return;
- }
- KSTATUS
- NetpEthernetSend (
- PVOID DataLinkContext,
- PNET_PACKET_LIST PacketList,
- PNETWORK_ADDRESS SourcePhysicalAddress,
- PNETWORK_ADDRESS DestinationPhysicalAddress,
- ULONG ProtocolNumber
- )
- /*++
- Routine Description:
- This routine sends data through the data link layer and out the link.
- Arguments:
- DataLinkContext - Supplies a pointer to the data link context for the
- link on which to send the data.
- PacketList - Supplies a pointer to a list of network packets to send. Data
- in these packets may be modified by this routine, but must not be used
- once this routine returns.
- SourcePhysicalAddress - Supplies a pointer to the source (local) physical
- network address.
- DestinationPhysicalAddress - Supplies the optional physical address of the
- destination, or at least the next hop. If NULL is provided, then the
- packets will be sent to the data link layer's broadcast address.
- ProtocolNumber - Supplies the protocol number of the data inside the data
- link header.
- Return Value:
- Status code.
- --*/
- {
- ULONG ByteIndex;
- PUCHAR CurrentElement;
- PLIST_ENTRY CurrentEntry;
- PVOID DeviceContext;
- PNET_LINK Link;
- PNET_PACKET_BUFFER Packet;
- KSTATUS Status;
- Link = (PNET_LINK)DataLinkContext;
- CurrentEntry = PacketList->Head.Next;
- while (CurrentEntry != &(PacketList->Head)) {
- Packet = LIST_VALUE(CurrentEntry, NET_PACKET_BUFFER, ListEntry);
- CurrentEntry = CurrentEntry->Next;
- ASSERT(Packet->DataOffset >= ETHERNET_HEADER_SIZE);
- //
- // The length should not be bigger than the maximum allowed ethernet
- // packet.
- //
- ASSERT((Packet->FooterOffset - Packet->DataOffset) <=
- ETHERNET_MAXIMUM_PAYLOAD_SIZE);
- //
- // Copy the destination address.
- //
- Packet->DataOffset -= ETHERNET_HEADER_SIZE;
- CurrentElement = Packet->Buffer + Packet->DataOffset;
- if (DestinationPhysicalAddress != NULL) {
- RtlCopyMemory(CurrentElement,
- &(DestinationPhysicalAddress->Address),
- ETHERNET_ADDRESS_SIZE);
- CurrentElement += ETHERNET_ADDRESS_SIZE;
- //
- // If no destination address was supplied, use the broadcast address.
- //
- } else {
- for (ByteIndex = 0;
- ByteIndex < ETHERNET_ADDRESS_SIZE;
- ByteIndex += 1) {
- *CurrentElement = 0xFF;
- CurrentElement += 1;
- }
- }
- //
- // Copy the source address.
- //
- RtlCopyMemory(CurrentElement,
- &(SourcePhysicalAddress->Address),
- ETHERNET_ADDRESS_SIZE);
- CurrentElement += ETHERNET_ADDRESS_SIZE;
- //
- // Copy the protocol number.
- //
- *((PUSHORT)CurrentElement) = CPU_TO_NETWORK16((USHORT)ProtocolNumber);
- }
- DeviceContext = Link->Properties.DeviceContext;
- Status = Link->Properties.Interface.Send(DeviceContext, PacketList);
- //
- // If the link layer returns that the resource is in use it means it was
- // too busy to send all of the packets. Release the packets for it and
- // convert this into a success status.
- //
- if (Status == STATUS_RESOURCE_IN_USE) {
- if ((EthernetDebugFlags & ETHERNET_DEBUG_FLAG_DROPPED_PACKETS) != 0) {
- RtlDebugPrint("ETH: Link layer dropped %d packets.\n",
- PacketList->Count);
- }
- NetDestroyBufferList(PacketList);
- Status = STATUS_SUCCESS;
- }
- return Status;
- }
- VOID
- NetpEthernetProcessReceivedPacket (
- PVOID DataLinkContext,
- PNET_PACKET_BUFFER Packet
- )
- /*++
- Routine Description:
- This routine is called to process a received ethernet packet.
- Arguments:
- DataLinkContext - Supplies a pointer to the data link context for the link
- that received the packet.
- Packet - Supplies a pointer to a structure describing the incoming packet.
- This structure may be used as a scratch space while this routine
- executes and the packet travels up the stack, but will not be accessed
- after this routine returns.
- Return Value:
- None. When the function returns, the memory associated with the packet may
- be reclaimed and reused.
- --*/
- {
- PNET_LINK Link;
- PNET_NETWORK_ENTRY NetworkEntry;
- ULONG NetworkProtocol;
- Link = (PNET_LINK)DataLinkContext;
- //
- // Get the network layer to deal with this.
- //
- NetworkProtocol = *((PUSHORT)(Packet->Buffer + Packet->DataOffset +
- (2 * ETHERNET_ADDRESS_SIZE)));
- NetworkProtocol = NETWORK_TO_CPU16(NetworkProtocol);
- NetworkEntry = NetGetNetworkEntry(NetworkProtocol);
- if (NetworkEntry == NULL) {
- RtlDebugPrint("Unknown protocol number 0x%x found in ethernet "
- "header.\n",
- NetworkProtocol);
- return;
- }
- //
- // Strip off the source MAC address, destination MAC address, and protocol
- // number.
- //
- Packet->DataOffset += (2 * ETHERNET_ADDRESS_SIZE) + sizeof(USHORT);
- NetworkEntry->Interface.ProcessReceivedData(Link, Packet);
- return;
- }
- VOID
- NetpEthernetGetBroadcastAddress (
- PNETWORK_ADDRESS PhysicalNetworkAddress
- )
- /*++
- Routine Description:
- This routine gets the ethernet broadcast address.
- Arguments:
- PhysicalNetworkAddress - Supplies a pointer where the physical network
- broadcast address will be returned.
- Return Value:
- None.
- --*/
- {
- ULONG ByteIndex;
- PUCHAR BytePointer;
- BytePointer = (PUCHAR)(PhysicalNetworkAddress->Address);
- RtlZeroMemory(BytePointer, sizeof(PhysicalNetworkAddress->Address));
- PhysicalNetworkAddress->Domain = NetDomainEthernet;
- PhysicalNetworkAddress->Port = 0;
- for (ByteIndex = 0; ByteIndex < ETHERNET_ADDRESS_SIZE; ByteIndex += 1) {
- BytePointer[ByteIndex] = 0xFF;
- }
- return;
- }
- ULONG
- NetpEthernetPrintAddress (
- PNETWORK_ADDRESS Address,
- PSTR Buffer,
- ULONG BufferLength
- )
- /*++
- Routine Description:
- This routine is called to convert a network address into a string, or
- determine the length of the buffer needed to convert an address into a
- string.
- Arguments:
- Address - Supplies an optional pointer to a network address to convert to
- a string.
- Buffer - Supplies an optional pointer where the string representation of
- the address will be returned.
- BufferLength - Supplies the length of the supplied buffer, in bytes.
- Return Value:
- Returns the maximum length of any address if no network address is
- supplied.
- Returns the actual length of the network address string if a network address
- was supplied, including the null terminator.
- --*/
- {
- PUCHAR BytePointer;
- ULONG Length;
- if (Address == NULL) {
- return ETHERNET_STRING_LENGTH;
- }
- ASSERT(Address->Domain == NetDomainEthernet);
- BytePointer = (PUCHAR)(Address->Address);
- Length = RtlPrintToString(Buffer,
- BufferLength,
- CharacterEncodingAscii,
- "%02X:%02X:%02X:%02X:%02X:%02X",
- BytePointer[0],
- BytePointer[1],
- BytePointer[2],
- BytePointer[3],
- BytePointer[4],
- BytePointer[5]);
- return Length;
- }
- VOID
- NetpEthernetGetPacketSizeInformation (
- PVOID DataLinkContext,
- PNET_PACKET_SIZE_INFORMATION PacketSizeInformation,
- ULONG Flags
- )
- /*++
- Routine Description:
- This routine gets the current packet size information for the given link.
- As the number of required headers can be different for each link, the
- packet size information is not a constant for an entire data link layer.
- Arguments:
- DataLinkContext - Supplies a pointer to the data link context of the link
- whose packet size information is being queried.
- PacketSizeInformation - Supplies a pointer to a structure that receives the
- link's data link layer packet size information.
- Flags - Supplies a bitmask of flags indicating which packet size
- information is desired. See NET_PACKET_SIZE_FLAG_* for definitions.
- Return Value:
- None.
- --*/
- {
- PacketSizeInformation->HeaderSize = ETHERNET_HEADER_SIZE;
- PacketSizeInformation->FooterSize = 0;
- PacketSizeInformation->MaxPacketSize = ETHERNET_HEADER_SIZE +
- ETHERNET_MAXIMUM_PAYLOAD_SIZE;
- PacketSizeInformation->MinPacketSize = ETHERNET_HEADER_SIZE +
- ETHERNET_MINIMUM_PAYLOAD_SIZE +
- ETHERNET_FOOTER_SIZE;
- return;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- KSTATUS
- NetpEthernetGetEthernetAddressFromSmbios (
- PULONG Address
- )
- /*++
- Routine Description:
- This routine attempts to use the SMBIOS structures to invent a platform
- unique ethernet address.
- Arguments:
- Address - Supplies a pointer where the lower 32 bits of the address will
- be returned on success.
- Return Value:
- Returns the maximum length of any address if no network address is
- supplied.
- Returns the actual length of the network address string if a network address
- was supplied, including the null terminator.
- --*/
- {
- PSMBIOS_ENTRY_POINT EntryPoint;
- EntryPoint = AcpiFindTable(SMBIOS_ANCHOR_STRING_VALUE, NULL);
- if (EntryPoint == NULL) {
- return STATUS_NOT_FOUND;
- }
- //
- // Compute the CRC32 of the SMBIOS table structures, hoping that comes out
- // unique per platform.
- //
- *Address = RtlComputeCrc32(0,
- EntryPoint + 1,
- EntryPoint->StructureTableLength);
- return STATUS_SUCCESS;
- }
|