ethernet.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890
  1. /*++
  2. Copyright (c) 2013 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. ethernet.c
  9. Abstract:
  10. This module implements functionality for Ethernet-based links.
  11. Author:
  12. Evan Green 5-Apr-2013
  13. Environment:
  14. Kernel
  15. --*/
  16. //
  17. // ------------------------------------------------------------------- Includes
  18. //
  19. //
  20. // Data link layer drivers are supposed to be able to stand on their own (ie be
  21. // able to be implemented outside the core net library). For the builtin ones,
  22. // avoid including netcore.h, but still redefine those functions that would
  23. // otherwise generate imports.
  24. //
  25. #define NET_API __DLLEXPORT
  26. #include <minoca/kernel/driver.h>
  27. #include <minoca/net/netdrv.h>
  28. #include <minoca/net/ip4.h>
  29. #include <minoca/net/ip6.h>
  30. #include <minoca/kernel/acpi.h>
  31. #include <minoca/fw/smbios.h>
  32. #include "ethernet.h"
  33. //
  34. // ---------------------------------------------------------------- Definitions
  35. //
  36. #define ETHERNET_ALLOCATION_TAG 0x72687445 // 'rhtE'
  37. //
  38. // Printed strings of ethernet addresses look something like:
  39. // "12:34:56:78:9A:BC". Include the null terminator.
  40. //
  41. #define ETHERNET_STRING_LENGTH 18
  42. //
  43. // Define the Ethernet debug flags.
  44. //
  45. #define ETHERNET_DEBUG_FLAG_DROPPED_PACKETS 0x00000001
  46. //
  47. // Define the IPv4 address mask for the bits that get included in a multicast
  48. // MAC address.
  49. //
  50. #define ETHERNET_IP4_MULTICAST_TO_MAC_MASK CPU_TO_NETWORK32(0x007FFFFF)
  51. //
  52. // ------------------------------------------------------ Data Type Definitions
  53. //
  54. //
  55. // ----------------------------------------------- Internal Function Prototypes
  56. //
  57. KSTATUS
  58. NetpEthernetInitializeLink (
  59. PNET_LINK Link
  60. );
  61. VOID
  62. NetpEthernetDestroyLink (
  63. PNET_LINK Link
  64. );
  65. KSTATUS
  66. NetpEthernetSend (
  67. PVOID DataLinkContext,
  68. PNET_PACKET_LIST PacketList,
  69. PNETWORK_ADDRESS SourcePhysicalAddress,
  70. PNETWORK_ADDRESS DestinationPhysicalAddress,
  71. ULONG ProtocolNumber
  72. );
  73. VOID
  74. NetpEthernetProcessReceivedPacket (
  75. PVOID DataLinkContext,
  76. PNET_PACKET_BUFFER Packet
  77. );
  78. KSTATUS
  79. NetpEthernetConvertToPhysicalAddress (
  80. PNETWORK_ADDRESS NetworkAddress,
  81. PNETWORK_ADDRESS PhysicalAddress,
  82. NET_ADDRESS_TYPE NetworkAddressType
  83. );
  84. ULONG
  85. NetpEthernetPrintAddress (
  86. PNETWORK_ADDRESS Address,
  87. PSTR Buffer,
  88. ULONG BufferLength
  89. );
  90. VOID
  91. NetpEthernetGetPacketSizeInformation (
  92. PVOID DataLinkContext,
  93. PNET_PACKET_SIZE_INFORMATION PacketSizeInformation,
  94. ULONG Flags
  95. );
  96. KSTATUS
  97. NetpEthernetGetEthernetAddressFromSmbios (
  98. PULONG Address
  99. );
  100. //
  101. // -------------------------------------------------------------------- Globals
  102. //
  103. //
  104. // Store the lower 4 bytes of the created MAC address base. This value is
  105. // incremented for each ethernet card that comes online without an assigned
  106. // ethernet address.
  107. //
  108. ULONG NetEthernetInventedAddress;
  109. //
  110. // Store a bitmask of debug flags.
  111. //
  112. ULONG EthernetDebugFlags = 0;
  113. //
  114. // Stores the base MAC address for all IPv4 multicast addresses. The lower 23
  115. // bits are taken from the lower 23-bits of the IPv4 address.
  116. //
  117. UCHAR NetEthernetIp4MulticastBase[ETHERNET_ADDRESS_SIZE] =
  118. {0x01, 0x00, 0x5E, 0x00, 0x00, 0x00};
  119. //
  120. // Stores the base MAC address for all IPv6 multicast addresses. The last four
  121. // bytes are taken from last four bytes of the IPv6 address.
  122. //
  123. UCHAR NetEthernetIp6MulticastBase[ETHERNET_ADDRESS_SIZE] =
  124. {0x33, 0x33, 0x00, 0x00, 0x00, 0x00};
  125. //
  126. // ------------------------------------------------------------------ Functions
  127. //
  128. VOID
  129. NetpEthernetInitialize (
  130. VOID
  131. )
  132. /*++
  133. Routine Description:
  134. This routine initializes support for Ethernet frames.
  135. Arguments:
  136. None.
  137. Return Value:
  138. None.
  139. --*/
  140. {
  141. NET_DATA_LINK_ENTRY DataLinkEntry;
  142. HANDLE DataLinkHandle;
  143. PNET_DATA_LINK_INTERFACE Interface;
  144. KSTATUS Status;
  145. DataLinkEntry.Domain = NetDomainEthernet;
  146. Interface = &(DataLinkEntry.Interface);
  147. Interface->InitializeLink = NetpEthernetInitializeLink;
  148. Interface->DestroyLink = NetpEthernetDestroyLink;
  149. Interface->Send = NetpEthernetSend;
  150. Interface->ProcessReceivedPacket = NetpEthernetProcessReceivedPacket;
  151. Interface->ConvertToPhysicalAddress = NetpEthernetConvertToPhysicalAddress;
  152. Interface->PrintAddress = NetpEthernetPrintAddress;
  153. Interface->GetPacketSizeInformation = NetpEthernetGetPacketSizeInformation;
  154. Status = NetRegisterDataLinkLayer(&DataLinkEntry, &DataLinkHandle);
  155. if (!KSUCCESS(Status)) {
  156. ASSERT(FALSE);
  157. }
  158. return;
  159. }
  160. NET_API
  161. BOOL
  162. NetIsEthernetAddressValid (
  163. BYTE Address[ETHERNET_ADDRESS_SIZE]
  164. )
  165. /*++
  166. Routine Description:
  167. This routine determines if the given ethernet address is a valid individual
  168. address or not. This routine returns FALSE for 00:00:00:00:00:00 and
  169. FF:FF:FF:FF:FF:FF, and TRUE for everything else.
  170. Arguments:
  171. Address - Supplies the address to check.
  172. Return Value:
  173. TRUE if the ethernet address is a valid individual address.
  174. FALSE if the address is not valid.
  175. --*/
  176. {
  177. if ((Address[0] == 0) && (Address[1] == 0) && (Address[2] == 0) &&
  178. (Address[3] == 0) && (Address[4] == 0) && (Address[5] == 0)) {
  179. return FALSE;
  180. }
  181. if ((Address[0] == 0xFF) && (Address[1] == 0xFF) && (Address[2] == 0xFF) &&
  182. (Address[3] == 0xFF) && (Address[4] == 0xFF) && (Address[5] == 0xFF)) {
  183. return FALSE;
  184. }
  185. return TRUE;
  186. }
  187. NET_API
  188. VOID
  189. NetCreateEthernetAddress (
  190. BYTE Address[ETHERNET_ADDRESS_SIZE]
  191. )
  192. /*++
  193. Routine Description:
  194. This routine generates a random ethernet address.
  195. Arguments:
  196. Address - Supplies the array where the new address will be stored.
  197. Return Value:
  198. None.
  199. --*/
  200. {
  201. RUNLEVEL OldRunLevel;
  202. KSTATUS Status;
  203. ULONG Value;
  204. //
  205. // If no base has been assigned yet, get a random one.
  206. //
  207. if (NetEthernetInventedAddress == 0) {
  208. //
  209. // Use the SMBIOS table, which should hopefully have a platform
  210. // identifier in it, to compute an address that is unique to the
  211. // platform but remains constant across reboots. The beauty of this if
  212. // it works is it doesn't require any unique numbers to be stored in
  213. // the OS image.
  214. //
  215. Status = NetpEthernetGetEthernetAddressFromSmbios(
  216. &NetEthernetInventedAddress);
  217. if (KSUCCESS(Status)) {
  218. Value = NetEthernetInventedAddress;
  219. //
  220. // If there is no SMBIOS table, use the processor counter to make a
  221. // random address up. This unfortunately changes across reboots.
  222. //
  223. } else {
  224. OldRunLevel = KeRaiseRunLevel(RunLevelDispatch);
  225. Value = HlQueryProcessorCounter() * 12345;
  226. KeLowerRunLevel(OldRunLevel);
  227. NetEthernetInventedAddress = Value;
  228. }
  229. } else {
  230. Value = RtlAtomicAdd32(&NetEthernetInventedAddress, 1);
  231. }
  232. //
  233. // Set the first byte to 2 to indicate a locally administered unicast
  234. // address.
  235. //
  236. Address[0] = 0x02;
  237. Address[1] = 0x00;
  238. RtlCopyMemory(&(Address[sizeof(USHORT)]), &Value, sizeof(ULONG));
  239. return;
  240. }
  241. KSTATUS
  242. NetpEthernetInitializeLink (
  243. PNET_LINK Link
  244. )
  245. /*++
  246. Routine Description:
  247. This routine initializes any pieces of information needed by the data link
  248. layer for a new link.
  249. Arguments:
  250. Link - Supplies a pointer to the new link.
  251. Return Value:
  252. Status code.
  253. --*/
  254. {
  255. //
  256. // Ethernet does not need any extra state. It just expects to get the
  257. // network link passed back as the data context. No extra references on the
  258. // network link are taken because this data link context gets "destroyed"
  259. // when the network link's last reference is released.
  260. //
  261. Link->DataLinkContext = Link;
  262. return STATUS_SUCCESS;
  263. }
  264. VOID
  265. NetpEthernetDestroyLink (
  266. PNET_LINK Link
  267. )
  268. /*++
  269. Routine Description:
  270. This routine allows the data link layer to tear down any state before a
  271. link is destroyed.
  272. Arguments:
  273. Link - Supplies a pointer to the dying link.
  274. Return Value:
  275. None.
  276. --*/
  277. {
  278. Link->DataLinkContext = NULL;
  279. return;
  280. }
  281. KSTATUS
  282. NetpEthernetSend (
  283. PVOID DataLinkContext,
  284. PNET_PACKET_LIST PacketList,
  285. PNETWORK_ADDRESS SourcePhysicalAddress,
  286. PNETWORK_ADDRESS DestinationPhysicalAddress,
  287. ULONG ProtocolNumber
  288. )
  289. /*++
  290. Routine Description:
  291. This routine sends data through the data link layer and out the link.
  292. Arguments:
  293. DataLinkContext - Supplies a pointer to the data link context for the
  294. link on which to send the data.
  295. PacketList - Supplies a pointer to a list of network packets to send. Data
  296. in these packets may be modified by this routine, but must not be used
  297. once this routine returns.
  298. SourcePhysicalAddress - Supplies a pointer to the source (local) physical
  299. network address.
  300. DestinationPhysicalAddress - Supplies the optional physical address of the
  301. destination, or at least the next hop. If NULL is provided, then the
  302. packets will be sent to the data link layer's broadcast address.
  303. ProtocolNumber - Supplies the protocol number of the data inside the data
  304. link header.
  305. Return Value:
  306. Status code.
  307. --*/
  308. {
  309. ULONG ByteIndex;
  310. PUCHAR CurrentElement;
  311. PLIST_ENTRY CurrentEntry;
  312. PVOID DeviceContext;
  313. PNET_LINK Link;
  314. PNET_PACKET_BUFFER Packet;
  315. KSTATUS Status;
  316. Link = (PNET_LINK)DataLinkContext;
  317. CurrentEntry = PacketList->Head.Next;
  318. while (CurrentEntry != &(PacketList->Head)) {
  319. Packet = LIST_VALUE(CurrentEntry, NET_PACKET_BUFFER, ListEntry);
  320. CurrentEntry = CurrentEntry->Next;
  321. ASSERT(Packet->DataOffset >= ETHERNET_HEADER_SIZE);
  322. //
  323. // The length should not be bigger than the maximum allowed ethernet
  324. // packet.
  325. //
  326. ASSERT((Packet->FooterOffset - Packet->DataOffset) <=
  327. ETHERNET_MAXIMUM_PAYLOAD_SIZE);
  328. //
  329. // Copy the destination address.
  330. //
  331. Packet->DataOffset -= ETHERNET_HEADER_SIZE;
  332. CurrentElement = Packet->Buffer + Packet->DataOffset;
  333. if (DestinationPhysicalAddress != NULL) {
  334. RtlCopyMemory(CurrentElement,
  335. &(DestinationPhysicalAddress->Address),
  336. ETHERNET_ADDRESS_SIZE);
  337. CurrentElement += ETHERNET_ADDRESS_SIZE;
  338. //
  339. // If no destination address was supplied, use the broadcast address.
  340. //
  341. } else {
  342. for (ByteIndex = 0;
  343. ByteIndex < ETHERNET_ADDRESS_SIZE;
  344. ByteIndex += 1) {
  345. *CurrentElement = 0xFF;
  346. CurrentElement += 1;
  347. }
  348. }
  349. //
  350. // Copy the source address.
  351. //
  352. RtlCopyMemory(CurrentElement,
  353. &(SourcePhysicalAddress->Address),
  354. ETHERNET_ADDRESS_SIZE);
  355. CurrentElement += ETHERNET_ADDRESS_SIZE;
  356. //
  357. // Copy the protocol number.
  358. //
  359. *((PUSHORT)CurrentElement) = CPU_TO_NETWORK16((USHORT)ProtocolNumber);
  360. }
  361. DeviceContext = Link->Properties.DeviceContext;
  362. Status = Link->Properties.Interface.Send(DeviceContext, PacketList);
  363. //
  364. // If the link layer returns that the resource is in use it means it was
  365. // too busy to send all of the packets. Release the packets for it and
  366. // convert this into a success status.
  367. //
  368. if (Status == STATUS_RESOURCE_IN_USE) {
  369. if ((EthernetDebugFlags & ETHERNET_DEBUG_FLAG_DROPPED_PACKETS) != 0) {
  370. RtlDebugPrint("ETH: Link layer dropped %d packets.\n",
  371. PacketList->Count);
  372. }
  373. NetDestroyBufferList(PacketList);
  374. Status = STATUS_SUCCESS;
  375. }
  376. return Status;
  377. }
  378. VOID
  379. NetpEthernetProcessReceivedPacket (
  380. PVOID DataLinkContext,
  381. PNET_PACKET_BUFFER Packet
  382. )
  383. /*++
  384. Routine Description:
  385. This routine is called to process a received ethernet packet.
  386. Arguments:
  387. DataLinkContext - Supplies a pointer to the data link context for the link
  388. that received the packet.
  389. Packet - Supplies a pointer to a structure describing the incoming packet.
  390. This structure may be used as a scratch space while this routine
  391. executes and the packet travels up the stack, but will not be accessed
  392. after this routine returns.
  393. Return Value:
  394. None. When the function returns, the memory associated with the packet may
  395. be reclaimed and reused.
  396. --*/
  397. {
  398. PNET_LINK Link;
  399. PNET_NETWORK_ENTRY NetworkEntry;
  400. ULONG NetworkProtocol;
  401. NET_RECEIVE_CONTEXT ReceiveContext;
  402. Link = (PNET_LINK)DataLinkContext;
  403. //
  404. // Get the network layer to deal with this.
  405. //
  406. NetworkProtocol = *((PUSHORT)(Packet->Buffer + Packet->DataOffset +
  407. (2 * ETHERNET_ADDRESS_SIZE)));
  408. NetworkProtocol = NETWORK_TO_CPU16(NetworkProtocol);
  409. NetworkEntry = NetGetNetworkEntry(NetworkProtocol);
  410. if (NetworkEntry == NULL) {
  411. RtlDebugPrint("Unknown protocol number 0x%x found in ethernet "
  412. "header.\n",
  413. NetworkProtocol);
  414. return;
  415. }
  416. //
  417. // Strip off the source MAC address, destination MAC address, and protocol
  418. // number.
  419. //
  420. Packet->DataOffset += (2 * ETHERNET_ADDRESS_SIZE) + sizeof(USHORT);
  421. RtlZeroMemory(&ReceiveContext, sizeof(NET_RECEIVE_CONTEXT));
  422. ReceiveContext.Packet = Packet;
  423. ReceiveContext.Link = Link;
  424. ReceiveContext.Network = NetworkEntry;
  425. NetworkEntry->Interface.ProcessReceivedData(&ReceiveContext);
  426. return;
  427. }
  428. KSTATUS
  429. NetpEthernetConvertToPhysicalAddress (
  430. PNETWORK_ADDRESS NetworkAddress,
  431. PNETWORK_ADDRESS PhysicalAddress,
  432. NET_ADDRESS_TYPE NetworkAddressType
  433. )
  434. /*++
  435. Routine Description:
  436. This routine converts the given network address to a physical layer address
  437. based on the provided network address type.
  438. Arguments:
  439. NetworkAddress - Supplies a pointer to the network layer address to convert.
  440. PhysicalAddress - Supplies a pointer to an address that receives the
  441. converted physical layer address.
  442. NetworkAddressType - Supplies the classified type of the given network
  443. address, which aids in conversion.
  444. Return Value:
  445. Status code.
  446. --*/
  447. {
  448. ULONG ByteIndex;
  449. PUCHAR BytePointer;
  450. ULONG Ip4AddressMask;
  451. PUCHAR Ip4BytePointer;
  452. PIP4_ADDRESS Ip4Multicast;
  453. PUCHAR Ip6BytePointer;
  454. KSTATUS Status;
  455. BytePointer = (PUCHAR)(PhysicalAddress->Address);
  456. RtlZeroMemory(BytePointer, sizeof(PhysicalAddress->Address));
  457. PhysicalAddress->Domain = NetDomainEthernet;
  458. PhysicalAddress->Port = 0;
  459. Status = STATUS_SUCCESS;
  460. switch (NetworkAddressType) {
  461. //
  462. // The broadcast address is the same for all network addresses.
  463. //
  464. case NetAddressBroadcast:
  465. for (ByteIndex = 0; ByteIndex < ETHERNET_ADDRESS_SIZE; ByteIndex += 1) {
  466. BytePointer[ByteIndex] = 0xFF;
  467. }
  468. break;
  469. //
  470. // A multicast MAC address depends on the domain of the given network
  471. // address. This conversion is done at the physical layer because the
  472. // network layer shouldn't need to know anything about the underlying
  473. // physical layer and the conversion algorithm is specific to the physical
  474. // layer's address type.
  475. //
  476. case NetAddressMulticast:
  477. switch (NetworkAddress->Domain) {
  478. case NetDomainIp4:
  479. //
  480. // The IPv4 address is in network byte order, but the CPU byte
  481. // order low 23-bits need to be added to the MAC address. Get the
  482. // low bytes, but keep them in network order to avoid doing a swap.
  483. //
  484. Ip4Multicast = (PIP4_ADDRESS)NetworkAddress;
  485. Ip4AddressMask = Ip4Multicast->Address &
  486. ETHERNET_IP4_MULTICAST_TO_MAC_MASK;
  487. //
  488. // Copy the static base MAC address.
  489. //
  490. RtlCopyMemory(BytePointer,
  491. NetEthernetIp4MulticastBase,
  492. ETHERNET_ADDRESS_SIZE);
  493. //
  494. // Add the low 23-bits from the IP address to the MAC address,
  495. // keeping in mind that the IP bytes are in network order.
  496. //
  497. Ip4BytePointer = (PUCHAR)&Ip4AddressMask;
  498. BytePointer[3] |= Ip4BytePointer[1];
  499. BytePointer[4] = Ip4BytePointer[2];
  500. BytePointer[5] = Ip4BytePointer[3];
  501. break;
  502. case NetDomainIp6:
  503. //
  504. // The IPv6 multicast MAC address is formed by taking the last four
  505. // bytes of the IPv6 address and prepending them with two bytes of
  506. // 0x33.
  507. //
  508. Ip6BytePointer = (PUCHAR)(NetworkAddress->Address);
  509. BytePointer[0] = NetEthernetIp6MulticastBase[0];
  510. BytePointer[1] = NetEthernetIp6MulticastBase[1];
  511. BytePointer[2] = Ip6BytePointer[12];
  512. BytePointer[3] = Ip6BytePointer[13];
  513. BytePointer[4] = Ip6BytePointer[14];
  514. BytePointer[5] = Ip6BytePointer[15];
  515. break;
  516. default:
  517. Status = STATUS_NOT_SUPPORTED;
  518. break;
  519. }
  520. break;
  521. default:
  522. Status = STATUS_INVALID_PARAMETER;
  523. break;
  524. }
  525. return Status;
  526. }
  527. ULONG
  528. NetpEthernetPrintAddress (
  529. PNETWORK_ADDRESS Address,
  530. PSTR Buffer,
  531. ULONG BufferLength
  532. )
  533. /*++
  534. Routine Description:
  535. This routine is called to convert a network address into a string, or
  536. determine the length of the buffer needed to convert an address into a
  537. string.
  538. Arguments:
  539. Address - Supplies an optional pointer to a network address to convert to
  540. a string.
  541. Buffer - Supplies an optional pointer where the string representation of
  542. the address will be returned.
  543. BufferLength - Supplies the length of the supplied buffer, in bytes.
  544. Return Value:
  545. Returns the maximum length of any address if no network address is
  546. supplied.
  547. Returns the actual length of the network address string if a network address
  548. was supplied, including the null terminator.
  549. --*/
  550. {
  551. PUCHAR BytePointer;
  552. ULONG Length;
  553. if (Address == NULL) {
  554. return ETHERNET_STRING_LENGTH;
  555. }
  556. ASSERT(Address->Domain == NetDomainEthernet);
  557. BytePointer = (PUCHAR)(Address->Address);
  558. Length = RtlPrintToString(Buffer,
  559. BufferLength,
  560. CharacterEncodingAscii,
  561. "%02X:%02X:%02X:%02X:%02X:%02X",
  562. BytePointer[0],
  563. BytePointer[1],
  564. BytePointer[2],
  565. BytePointer[3],
  566. BytePointer[4],
  567. BytePointer[5]);
  568. return Length;
  569. }
  570. VOID
  571. NetpEthernetGetPacketSizeInformation (
  572. PVOID DataLinkContext,
  573. PNET_PACKET_SIZE_INFORMATION PacketSizeInformation,
  574. ULONG Flags
  575. )
  576. /*++
  577. Routine Description:
  578. This routine gets the current packet size information for the given link.
  579. As the number of required headers can be different for each link, the
  580. packet size information is not a constant for an entire data link layer.
  581. Arguments:
  582. DataLinkContext - Supplies a pointer to the data link context of the link
  583. whose packet size information is being queried.
  584. PacketSizeInformation - Supplies a pointer to a structure that receives the
  585. link's data link layer packet size information.
  586. Flags - Supplies a bitmask of flags indicating which packet size
  587. information is desired. See NET_PACKET_SIZE_FLAG_* for definitions.
  588. Return Value:
  589. None.
  590. --*/
  591. {
  592. PacketSizeInformation->HeaderSize = ETHERNET_HEADER_SIZE;
  593. PacketSizeInformation->FooterSize = 0;
  594. PacketSizeInformation->MaxPacketSize = ETHERNET_HEADER_SIZE +
  595. ETHERNET_MAXIMUM_PAYLOAD_SIZE;
  596. PacketSizeInformation->MinPacketSize = ETHERNET_HEADER_SIZE +
  597. ETHERNET_MINIMUM_PAYLOAD_SIZE +
  598. ETHERNET_FOOTER_SIZE;
  599. return;
  600. }
  601. //
  602. // --------------------------------------------------------- Internal Functions
  603. //
  604. KSTATUS
  605. NetpEthernetGetEthernetAddressFromSmbios (
  606. PULONG Address
  607. )
  608. /*++
  609. Routine Description:
  610. This routine attempts to use the SMBIOS structures to invent a platform
  611. unique ethernet address.
  612. Arguments:
  613. Address - Supplies a pointer where the lower 32 bits of the address will
  614. be returned on success.
  615. Return Value:
  616. Returns the maximum length of any address if no network address is
  617. supplied.
  618. Returns the actual length of the network address string if a network address
  619. was supplied, including the null terminator.
  620. --*/
  621. {
  622. PSMBIOS_ENTRY_POINT EntryPoint;
  623. EntryPoint = AcpiFindTable(SMBIOS_ANCHOR_STRING_VALUE, NULL);
  624. if (EntryPoint == NULL) {
  625. return STATUS_NOT_FOUND;
  626. }
  627. //
  628. // Compute the CRC32 of the SMBIOS table structures, hoping that comes out
  629. // unique per platform.
  630. //
  631. *Address = RtlComputeCrc32(0,
  632. EntryPoint + 1,
  633. EntryPoint->StructureTableLength);
  634. return STATUS_SUCCESS;
  635. }