ethernet.c 17 KB

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