ethernet.c 17 KB

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