if.c 26 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151
  1. /*++
  2. Copyright (c) 2016 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. if.c
  9. Abstract:
  10. This module implements support for network interface enumeration.
  11. Author:
  12. Chris Stevens 21-Jul-2016
  13. Environment:
  14. User Mode C Library
  15. --*/
  16. //
  17. // ------------------------------------------------------------------- Includes
  18. //
  19. #include "libcp.h"
  20. #include <minoca/devinfo/net.h>
  21. #include <net/if.h>
  22. #include <net/if_dl.h>
  23. #include <net/if_types.h>
  24. #include <netinet/in.h>
  25. #include <ifaddrs.h>
  26. #include <errno.h>
  27. #include <stdlib.h>
  28. #include "net.h"
  29. //
  30. // --------------------------------------------------------------------- Macros
  31. //
  32. //
  33. // This routine returns the network name index for a given network domain.
  34. //
  35. #define CL_NETWORK_NAME_INDEX_FROM_DOMAIN(_Domain) \
  36. (((_Domain) - NET_DOMAIN_PHYSICAL_BASE) + CL_NETWORK_NAME_DOMAIN_OFFSET)
  37. //
  38. // ---------------------------------------------------------------- Definitions
  39. //
  40. #define CL_NETWORK_NAME_FORMAT_COUNT 3
  41. #define CL_NETWORK_NAME_LINK_LAYER_INDEX 0
  42. #define CL_NETWORK_NAME_DOMAIN_OFFSET 1
  43. //
  44. // ------------------------------------------------------ Data Type Definitions
  45. //
  46. //
  47. // ----------------------------------------------- Internal Function Prototypes
  48. //
  49. KSTATUS
  50. ClpGetNetworkDevices (
  51. PDEVICE_INFORMATION_RESULT *Devices,
  52. PULONG DeviceCount
  53. );
  54. KSTATUS
  55. ClpGetNetworkDeviceName (
  56. DEVICE_ID DeviceId,
  57. PSTR *Buffer,
  58. ULONG BufferLength
  59. );
  60. KSTATUS
  61. ClpCreateNetworkDeviceName (
  62. DEVICE_ID DeviceId,
  63. PCSTR FormatString,
  64. PSTR *Buffer,
  65. ULONG BufferLength
  66. );
  67. KSTATUS
  68. ClpGetNetworkDeviceDomain (
  69. DEVICE_ID DeviceId,
  70. PNET_DOMAIN_TYPE Domain
  71. );
  72. KSTATUS
  73. ClpGetNetworkDeviceInformation (
  74. DEVICE_ID DeviceId,
  75. PNETWORK_DEVICE_INFORMATION Information
  76. );
  77. KSTATUS
  78. ClpCreateNetworkInterfaceAddress (
  79. DEVICE_ID DeviceId,
  80. struct ifaddrs **Interface,
  81. struct ifaddrs **LinkInterface
  82. );
  83. VOID
  84. ClpDestroyNetworkInterfaceAddress (
  85. struct ifaddrs *Interface
  86. );
  87. //
  88. // -------------------------------------------------------------------- Globals
  89. //
  90. PCSTR ClNetworkNameFormats[CL_NETWORK_NAME_FORMAT_COUNT] = {
  91. "il%d",
  92. "eth%d",
  93. "wlan%d"
  94. };
  95. //
  96. // ------------------------------------------------------------------ Functions
  97. //
  98. LIBC_API
  99. struct if_nameindex *
  100. if_nameindex (
  101. void
  102. )
  103. /*++
  104. Routine Description:
  105. This routine returns an array of all the available network interfaces on
  106. the system.
  107. Arguments:
  108. None.
  109. Return Value:
  110. An array of interface structures on success. The end of the array is
  111. indicated by a structure with a 0 index and NULL name.
  112. NULL on error, and errno will be set to contain more information.
  113. --*/
  114. {
  115. UINTN AllocationSize;
  116. ULONG DeviceCount;
  117. PDEVICE_INFORMATION_RESULT Devices;
  118. ULONG Index;
  119. struct if_nameindex *Interfaces;
  120. KSTATUS Status;
  121. Devices = NULL;
  122. DeviceCount = 0;
  123. Devices = NULL;
  124. Interfaces = NULL;
  125. //
  126. // Enumerate all the devices that support getting network device
  127. // information.
  128. //
  129. Status = ClpGetNetworkDevices(&Devices, &DeviceCount);
  130. if (!KSUCCESS(Status)) {
  131. goto EnumerateDevicesEnd;
  132. }
  133. //
  134. // Allocate enough name-index structures, including a empty one for the end
  135. // of the array.
  136. //
  137. AllocationSize = sizeof(struct if_nameindex) * (DeviceCount + 1);
  138. Interfaces = malloc(AllocationSize);
  139. if (Interfaces == NULL) {
  140. Status = STATUS_INSUFFICIENT_RESOURCES;
  141. goto EnumerateDevicesEnd;
  142. }
  143. memset(Interfaces, 0, AllocationSize);
  144. for (Index = 0; Index < DeviceCount; Index += 1) {
  145. Status = ClpGetNetworkDeviceName(Devices[Index].DeviceId,
  146. &(Interfaces[Index].if_name),
  147. 0);
  148. if (!KSUCCESS(Status)) {
  149. break;
  150. }
  151. Interfaces[Index].if_index = (unsigned)Devices[Index].DeviceId;
  152. }
  153. Status = STATUS_SUCCESS;
  154. EnumerateDevicesEnd:
  155. if (Devices != NULL) {
  156. free(Devices);
  157. }
  158. if (!KSUCCESS(Status)) {
  159. if (Interfaces != NULL) {
  160. if_freenameindex(Interfaces);
  161. Interfaces = NULL;
  162. }
  163. errno = ClConvertKstatusToErrorNumber(Status);
  164. }
  165. return Interfaces;
  166. }
  167. LIBC_API
  168. void
  169. if_freenameindex (
  170. struct if_nameindex *Interfaces
  171. )
  172. /*++
  173. Routine Description:
  174. This routine releases an array of network interfaces.
  175. Arguments:
  176. Interfaces - Supplies a pointer to the array of network interfaces to
  177. release.
  178. Return Value:
  179. None.
  180. --*/
  181. {
  182. struct if_nameindex *Interface;
  183. Interface = Interfaces;
  184. while (Interface->if_name != NULL) {
  185. free(Interface->if_name);
  186. Interface += 1;
  187. }
  188. free(Interfaces);
  189. return;
  190. }
  191. LIBC_API
  192. char *
  193. if_indextoname (
  194. unsigned Index,
  195. char *Name
  196. )
  197. /*++
  198. Routine Description:
  199. This routine returns the name of the network interface with the given index.
  200. Arguments:
  201. Index - Supplies the index of a network interface.
  202. Name - Supplies a pointer to a buffer where the interface name will be
  203. stored. The buffer must be at least IF_NAMESIZE.
  204. Return Value:
  205. A pointer to the supplied name buffer on success.
  206. NULL on error, and errno will be set to contain more information.
  207. --*/
  208. {
  209. KSTATUS Status;
  210. Status = ClpGetNetworkDeviceName(Index, &Name, IF_NAMESIZE);
  211. if (!KSUCCESS(Status)) {
  212. return NULL;
  213. }
  214. return Name;
  215. }
  216. LIBC_API
  217. unsigned
  218. if_nametoindex (
  219. const char *Name
  220. )
  221. /*++
  222. Routine Description:
  223. This routine returns the index of the network interface with the given name.
  224. Arguments:
  225. Name - Supplies the name of a network interface.
  226. Return Value:
  227. The index of the network interface on success.
  228. 0 otherwise.
  229. --*/
  230. {
  231. ULONG DeviceId;
  232. PSTR DeviceName;
  233. CHAR DeviceNameBuffer[IF_NAMESIZE];
  234. ULONG FoundDeviceId;
  235. ULONG Index;
  236. ULONG ItemsScanned;
  237. BOOL Match;
  238. KSTATUS Status;
  239. FoundDeviceId = 0;
  240. for (Index = 0; Index < CL_NETWORK_NAME_FORMAT_COUNT; Index += 1) {
  241. Status = RtlStringScan((PSTR)Name,
  242. IF_NAMESIZE,
  243. ClNetworkNameFormats[Index],
  244. strlen(ClNetworkNameFormats[Index]) + 1,
  245. CharacterEncodingDefault,
  246. &ItemsScanned,
  247. &DeviceId);
  248. //
  249. // On success, make sure the device ID corresponds to an actual device
  250. // by matching the name.
  251. //
  252. if (KSUCCESS(Status)) {
  253. DeviceName = &(DeviceNameBuffer[0]);
  254. Status = ClpGetNetworkDeviceName(DeviceId,
  255. &DeviceName,
  256. IF_NAMESIZE);
  257. if (KSUCCESS(Status)) {
  258. Match = RtlAreStringsEqual((PSTR)Name, DeviceName, IF_NAMESIZE);
  259. if (Match != FALSE) {
  260. FoundDeviceId = DeviceId;
  261. }
  262. }
  263. break;
  264. }
  265. }
  266. return FoundDeviceId;
  267. }
  268. LIBC_API
  269. int
  270. getifaddrs (
  271. struct ifaddrs **Interfaces
  272. )
  273. /*++
  274. Routine Description:
  275. This routine creates a linked list of network interfaces structures
  276. describing all of the network interfaces on the local system.
  277. Arguments:
  278. Interfaces - Supplies a pointer that receives a pointer to the linked list
  279. of network interfaces.
  280. Return Value:
  281. 0 on success.
  282. -1 on failure, and errno will be set to indicate the error.
  283. --*/
  284. {
  285. ULONG DeviceCount;
  286. PDEVICE_INFORMATION_RESULT Devices;
  287. ULONG Index;
  288. struct ifaddrs *Interface;
  289. struct ifaddrs *LinkInterface;
  290. struct ifaddrs **PreviousNextPointer;
  291. KSTATUS Status;
  292. Devices = NULL;
  293. DeviceCount = 0;
  294. Devices = NULL;
  295. Interface = NULL;
  296. *Interfaces = NULL;
  297. //
  298. // Enumerate all the devices that support getting network device
  299. // information.
  300. //
  301. Status = ClpGetNetworkDevices(&Devices, &DeviceCount);
  302. if (!KSUCCESS(Status)) {
  303. goto EnumerateInterfacesEnd;
  304. }
  305. //
  306. // Get the network information for each device and convert it to a network
  307. // interface address structure.
  308. //
  309. PreviousNextPointer = Interfaces;
  310. for (Index = 0; Index < DeviceCount; Index += 1) {
  311. Status = ClpCreateNetworkInterfaceAddress(Devices[Index].DeviceId,
  312. &Interface,
  313. &LinkInterface);
  314. if (!KSUCCESS(Status)) {
  315. break;
  316. }
  317. *PreviousNextPointer = Interface;
  318. Interface->ifa_next = LinkInterface;
  319. PreviousNextPointer = &(LinkInterface->ifa_next);
  320. }
  321. Status = STATUS_SUCCESS;
  322. EnumerateInterfacesEnd:
  323. if (Devices != NULL) {
  324. free(Devices);
  325. }
  326. if (!KSUCCESS(Status)) {
  327. if (*Interfaces != NULL) {
  328. freeifaddrs(*Interfaces);
  329. *Interfaces = NULL;
  330. }
  331. errno = ClConvertKstatusToErrorNumber(Status);
  332. return -1;
  333. }
  334. return 0;
  335. }
  336. LIBC_API
  337. void
  338. freeifaddrs (
  339. struct ifaddrs *Interfaces
  340. )
  341. /*++
  342. Routine Description:
  343. This routine releases a list of network interfaces.
  344. Arguments:
  345. Interfaces - Supplies a pointer to the list of network interfaces to
  346. release.
  347. Return Value:
  348. None.
  349. --*/
  350. {
  351. struct ifaddrs *Interface;
  352. struct ifaddrs *NextInterface;
  353. Interface = Interfaces;
  354. while (Interface != NULL) {
  355. NextInterface = Interface->ifa_next;
  356. ClpDestroyNetworkInterfaceAddress(Interface);
  357. Interface = NextInterface;
  358. }
  359. return;
  360. }
  361. //
  362. // --------------------------------------------------------- Internal Functions
  363. //
  364. KSTATUS
  365. ClpGetNetworkDevices (
  366. PDEVICE_INFORMATION_RESULT *Devices,
  367. PULONG DeviceCount
  368. )
  369. /*++
  370. Routine Description:
  371. This routine gets the list of network devices present on the system.
  372. Arguments:
  373. Devices - Supplies a pointer that receives a pointer to an array of network
  374. device information results. The caller is responsible for releasing the
  375. resources.
  376. DeviceCount - Supplies a pointer that receives the number of network device
  377. information results returned in the array.
  378. Return Value:
  379. Status code.
  380. --*/
  381. {
  382. UINTN AllocationSize;
  383. ULONG ResultCount;
  384. PDEVICE_INFORMATION_RESULT Results;
  385. KSTATUS Status;
  386. ResultCount = 0;
  387. Results = NULL;
  388. //
  389. // Enumerate all the devices that support getting network device
  390. // information.
  391. //
  392. Status = OsLocateDeviceInformation(&ClNetworkDeviceInformationUuid,
  393. NULL,
  394. NULL,
  395. &ResultCount);
  396. if (Status != STATUS_BUFFER_TOO_SMALL) {
  397. goto GetNetworkDevicesEnd;
  398. }
  399. if (ResultCount == 0) {
  400. Status = STATUS_SUCCESS;
  401. goto GetNetworkDevicesEnd;
  402. }
  403. AllocationSize = sizeof(DEVICE_INFORMATION_RESULT) * ResultCount;
  404. Results = malloc(AllocationSize);
  405. if (Results == NULL) {
  406. Status = STATUS_INSUFFICIENT_RESOURCES;
  407. goto GetNetworkDevicesEnd;
  408. }
  409. memset(Results, 0, AllocationSize);
  410. Status = OsLocateDeviceInformation(&ClNetworkDeviceInformationUuid,
  411. NULL,
  412. Results,
  413. &ResultCount);
  414. if (!KSUCCESS(Status)) {
  415. goto GetNetworkDevicesEnd;
  416. }
  417. if (ResultCount == 0) {
  418. free(Results);
  419. Results = NULL;
  420. Status = STATUS_SUCCESS;
  421. goto GetNetworkDevicesEnd;
  422. }
  423. GetNetworkDevicesEnd:
  424. if (!KSUCCESS(Status)) {
  425. if (Results != NULL) {
  426. free(Results);
  427. Results = NULL;
  428. }
  429. ResultCount = 0;
  430. }
  431. *Devices = Results;
  432. *DeviceCount = ResultCount;
  433. return Status;
  434. }
  435. KSTATUS
  436. ClpGetNetworkDeviceName (
  437. DEVICE_ID DeviceId,
  438. PSTR *Buffer,
  439. ULONG BufferLength
  440. )
  441. /*++
  442. Routine Description:
  443. This routine gets the network device name for the given device ID.
  444. Arguments:
  445. DeviceId - Supplies the ID of a network device.
  446. Buffer - Supplies a pointer to a buffer that receives the device name
  447. string. If the buffer is NULL, then a buffer will be allocated for the
  448. caller to release.
  449. BufferLength - Supplies the length of the device name buffer.
  450. Return Value:
  451. Status code.
  452. --*/
  453. {
  454. NET_DOMAIN_TYPE Domain;
  455. PCSTR FormatString;
  456. ULONG Index;
  457. KSTATUS Status;
  458. Status = ClpGetNetworkDeviceDomain(DeviceId, &Domain);
  459. if (!KSUCCESS(Status)) {
  460. goto GetNetworkDeviceNameEnd;
  461. }
  462. ASSERT(Domain >= NET_DOMAIN_PHYSICAL_BASE);
  463. Index = CL_NETWORK_NAME_INDEX_FROM_DOMAIN(Domain);
  464. FormatString = ClNetworkNameFormats[Index];
  465. Status = ClpCreateNetworkDeviceName(DeviceId,
  466. FormatString,
  467. Buffer,
  468. BufferLength);
  469. if (!KSUCCESS(Status)) {
  470. goto GetNetworkDeviceNameEnd;
  471. }
  472. GetNetworkDeviceNameEnd:
  473. return Status;
  474. }
  475. KSTATUS
  476. ClpCreateNetworkDeviceName (
  477. DEVICE_ID DeviceId,
  478. PCSTR FormatString,
  479. PSTR *Buffer,
  480. ULONG BufferLength
  481. )
  482. /*++
  483. Routine Description:
  484. This routine creates a network device name based on the given device ID and
  485. the format string. The caller is expected to release the name if a NULL
  486. buffer is supplied.
  487. Arguments:
  488. DeviceId - Supplies the ID of a network device.
  489. FormatString - Supplies a pointer to the format string to use to create the
  490. device name.
  491. Buffer - Supplies a pointer to a buffer that receives the device name
  492. string. If the buffer is NULL, then a buffer will be allocated for the
  493. caller to release.
  494. BufferLength - Supplies the length of the device name buffer.
  495. Return Value:
  496. Status code.
  497. --*/
  498. {
  499. ULONG NameLength;
  500. KSTATUS Status;
  501. NameLength = RtlPrintToString(NULL,
  502. 0,
  503. CharacterEncodingDefault,
  504. FormatString,
  505. DeviceId);
  506. if (*Buffer != NULL) {
  507. if (BufferLength < NameLength) {
  508. Status = STATUS_BUFFER_TOO_SMALL;
  509. goto CreateNetworkDeviceNameEnd;
  510. }
  511. } else {
  512. *Buffer = malloc(NameLength);
  513. if (*Buffer == NULL) {
  514. Status = STATUS_INSUFFICIENT_RESOURCES;
  515. goto CreateNetworkDeviceNameEnd;
  516. }
  517. }
  518. NameLength = RtlPrintToString(*Buffer,
  519. NameLength,
  520. CharacterEncodingDefault,
  521. FormatString,
  522. DeviceId);
  523. Status = STATUS_SUCCESS;
  524. CreateNetworkDeviceNameEnd:
  525. return Status;
  526. }
  527. KSTATUS
  528. ClpGetNetworkDeviceDomain (
  529. DEVICE_ID DeviceId,
  530. PNET_DOMAIN_TYPE Domain
  531. )
  532. /*++
  533. Routine Description:
  534. This routine looks up the given device's network domain type.
  535. Arguments:
  536. DeviceId - Supplies the ID of a network device.
  537. Domain - Supplies a pointer that receives the network domain for the given
  538. network device ID.
  539. Return Value:
  540. Status code.
  541. --*/
  542. {
  543. NETWORK_DEVICE_INFORMATION Information;
  544. KSTATUS Status;
  545. Status = ClpGetNetworkDeviceInformation(DeviceId, &Information);
  546. if (!KSUCCESS(Status)) {
  547. return Status;
  548. }
  549. *Domain = Information.PhysicalAddress.Domain;
  550. return STATUS_SUCCESS;
  551. }
  552. KSTATUS
  553. ClpGetNetworkDeviceInformation (
  554. DEVICE_ID DeviceId,
  555. PNETWORK_DEVICE_INFORMATION Information
  556. )
  557. /*++
  558. Routine Description:
  559. This routine gets the network device information for the given device.
  560. Arguments:
  561. DeviceId - Supplies the ID of a network device.
  562. Information - Supplies a pointer to a structure that will receive the
  563. network device information on success.
  564. Return Value:
  565. Status code.
  566. --*/
  567. {
  568. UINTN DataSize;
  569. KSTATUS Status;
  570. //
  571. // Try the IPv4 network information.
  572. //
  573. DataSize = sizeof(NETWORK_DEVICE_INFORMATION);
  574. Information->Version = NETWORK_DEVICE_INFORMATION_VERSION;
  575. Information->Domain = NetDomainIp4;
  576. Status = OsGetSetDeviceInformation(DeviceId,
  577. &ClNetworkDeviceInformationUuid,
  578. Information,
  579. &DataSize,
  580. FALSE);
  581. if (KSUCCESS(Status)) {
  582. return Status;
  583. }
  584. //
  585. // If that was unsuccessful, try IPv6.
  586. //
  587. DataSize = sizeof(NETWORK_DEVICE_INFORMATION);
  588. Information->Version = NETWORK_DEVICE_INFORMATION_VERSION;
  589. Information->Domain = NetDomainIp6;
  590. Status = OsGetSetDeviceInformation(DeviceId,
  591. &ClNetworkDeviceInformationUuid,
  592. Information,
  593. &DataSize,
  594. FALSE);
  595. if (KSUCCESS(Status)) {
  596. return Status;
  597. }
  598. return Status;
  599. }
  600. KSTATUS
  601. ClpCreateNetworkInterfaceAddress (
  602. DEVICE_ID DeviceId,
  603. struct ifaddrs **Interface,
  604. struct ifaddrs **LinkInterface
  605. )
  606. /*++
  607. Routine Description:
  608. This routine creates network interface address structures for the network
  609. device indicated by the given device ID and for its associated link-layer
  610. address.
  611. Arguments:
  612. DeviceId - Supplies the ID of the network device for which the network
  613. interface address structure is to be created.
  614. Interface - Supplies a pointer that receives a pointer to a newly allocated
  615. network interface address structure. The caller is responsible for
  616. releasing the allocation.
  617. LinkInterface - Supplies a pointer that receives a pointer to a newly
  618. allocated network interface address structure for the link-layer
  619. associated with this network device. The caller is responsible for
  620. releasing the allocation.
  621. Return Value:
  622. Status code.
  623. --*/
  624. {
  625. ULONG Address;
  626. socklen_t AddressLength;
  627. size_t AllocationSize;
  628. struct sockaddr_in *Broadcast;
  629. size_t DataLength;
  630. NET_DOMAIN_TYPE Domain;
  631. PCSTR FormatString;
  632. ULONG Index;
  633. NETWORK_DEVICE_INFORMATION Information;
  634. struct sockaddr_dl *LinkAddress;
  635. size_t MaxDataLength;
  636. size_t NameLength;
  637. struct ifaddrs *NewInterface;
  638. struct ifaddrs *NewLinkInterface;
  639. KSTATUS Status;
  640. ULONG Subnet;
  641. NewInterface = NULL;
  642. NewLinkInterface = NULL;
  643. //
  644. // Query the system for the network information associated with this
  645. // device ID.
  646. //
  647. Status = ClpGetNetworkDeviceInformation(DeviceId, &Information);
  648. if (!KSUCCESS(Status)) {
  649. goto CreateNetworkInterfaceAddressEnd;
  650. }
  651. //
  652. // Create a C library network interface address structure based on the
  653. // network device information.
  654. //
  655. NewInterface = malloc(sizeof(struct ifaddrs));
  656. if (NewInterface == NULL) {
  657. Status = STATUS_INSUFFICIENT_RESOURCES;
  658. goto CreateNetworkInterfaceAddressEnd;
  659. }
  660. memset(NewInterface, 0, sizeof(struct ifaddrs));
  661. Domain = Information.PhysicalAddress.Domain;
  662. ASSERT(Domain >= NET_DOMAIN_PHYSICAL_BASE);
  663. Index = CL_NETWORK_NAME_INDEX_FROM_DOMAIN(Domain);
  664. FormatString = ClNetworkNameFormats[Index];
  665. Status = ClpCreateNetworkDeviceName(DeviceId,
  666. FormatString,
  667. &(NewInterface->ifa_name),
  668. 0);
  669. if (!KSUCCESS(Status)) {
  670. goto CreateNetworkInterfaceAddressEnd;
  671. }
  672. //
  673. // If the network device is present in the query, then consider it "up". It
  674. // is only "running" if it fully configured and ready to receive traffic.
  675. //
  676. NewInterface->ifa_flags = IFF_UP;
  677. if ((Information.Flags & NETWORK_DEVICE_FLAG_CONFIGURED) != 0) {
  678. NewInterface->ifa_flags |= IFF_RUNNING;
  679. }
  680. if (Information.Address.Domain != NetDomainInvalid) {
  681. NewInterface->ifa_addr = malloc(sizeof(struct sockaddr));
  682. if (NewInterface->ifa_addr == NULL) {
  683. Status = STATUS_INSUFFICIENT_RESOURCES;
  684. goto CreateNetworkInterfaceAddressEnd;
  685. }
  686. AddressLength = sizeof(struct sockaddr);
  687. Status = ClConvertFromNetworkAddress(&(Information.Address),
  688. NewInterface->ifa_addr,
  689. &AddressLength,
  690. NULL,
  691. 0);
  692. if (!KSUCCESS(Status)) {
  693. goto CreateNetworkInterfaceAddressEnd;
  694. }
  695. }
  696. if (Information.Subnet.Domain != NetDomainInvalid) {
  697. NewInterface->ifa_netmask = malloc(sizeof(struct sockaddr));
  698. if (NewInterface->ifa_netmask == NULL) {
  699. Status = STATUS_INSUFFICIENT_RESOURCES;
  700. goto CreateNetworkInterfaceAddressEnd;
  701. }
  702. AddressLength = sizeof(struct sockaddr);
  703. Status = ClConvertFromNetworkAddress(&(Information.Subnet),
  704. NewInterface->ifa_netmask,
  705. &AddressLength,
  706. NULL,
  707. 0);
  708. if (!KSUCCESS(Status)) {
  709. goto CreateNetworkInterfaceAddressEnd;
  710. }
  711. }
  712. //
  713. // Create a broadcast address if this is IPv4.
  714. //
  715. if ((Information.Address.Domain == NetDomainIp4) &&
  716. (Information.Subnet.Domain == NetDomainIp4)) {
  717. Broadcast = malloc(sizeof(struct sockaddr_in));
  718. if (Broadcast == NULL) {
  719. Status = STATUS_INSUFFICIENT_RESOURCES;
  720. goto CreateNetworkInterfaceAddressEnd;
  721. }
  722. memset(Broadcast, 0, sizeof(struct sockaddr_in));
  723. Broadcast->sin_family = AF_INET;
  724. Address = (ULONG)(Information.Address.Address[0]);
  725. Subnet = (ULONG)(Information.Subnet.Address[0]);
  726. Address &= Subnet;
  727. Address |= ~Subnet;
  728. Broadcast->sin_addr.s_addr = Address;
  729. NewInterface->ifa_broadaddr = (struct sockaddr *)Broadcast;
  730. NewInterface->ifa_flags |= IFF_BROADCAST;
  731. }
  732. //
  733. // Create a C library network interface structure for the link-layer
  734. // address. The native Minoca system returns both the link and socket layer
  735. // addresses together. The C library needs them separate.
  736. //
  737. NewLinkInterface = malloc(sizeof(struct ifaddrs));
  738. if (NewLinkInterface == NULL) {
  739. Status = STATUS_INSUFFICIENT_RESOURCES;
  740. goto CreateNetworkInterfaceAddressEnd;
  741. }
  742. memset(NewLinkInterface, 0, sizeof(struct ifaddrs));
  743. FormatString = ClNetworkNameFormats[CL_NETWORK_NAME_LINK_LAYER_INDEX];
  744. Status = ClpCreateNetworkDeviceName(DeviceId,
  745. FormatString,
  746. &(NewLinkInterface->ifa_name),
  747. 0);
  748. if (!KSUCCESS(Status)) {
  749. goto CreateNetworkInterfaceAddressEnd;
  750. }
  751. //
  752. // If the network device is present in the query, then consider it "up". It
  753. // is only "running" if it's fully configured and ready to receive traffic.
  754. //
  755. NewLinkInterface->ifa_flags = IFF_UP;
  756. if ((Information.Flags & NETWORK_DEVICE_FLAG_CONFIGURED) != 0) {
  757. NewLinkInterface->ifa_flags |= IFF_RUNNING;
  758. }
  759. if (Information.PhysicalAddress.Domain != NetDomainInvalid) {
  760. AllocationSize = sizeof(struct sockaddr_dl);
  761. MaxDataLength = AllocationSize -
  762. FIELD_OFFSET(struct sockaddr_dl, sdl_data);
  763. NameLength = strlen(NewLinkInterface->ifa_name);
  764. DataLength = NameLength + ETHERNET_ADDRESS_SIZE;
  765. if (DataLength > MaxDataLength) {
  766. AllocationSize += DataLength - MaxDataLength;
  767. }
  768. //
  769. // The name length better not be too long for the socket address
  770. // structure.
  771. //
  772. if (NameLength > MAX_UCHAR) {
  773. Status = STATUS_NAME_TOO_LONG;
  774. goto CreateNetworkInterfaceAddressEnd;
  775. }
  776. LinkAddress = malloc(AllocationSize);
  777. if (LinkAddress == NULL) {
  778. Status = STATUS_INSUFFICIENT_RESOURCES;
  779. goto CreateNetworkInterfaceAddressEnd;
  780. }
  781. RtlZeroMemory(LinkAddress, AllocationSize);
  782. LinkAddress->sdl_len = AllocationSize;
  783. LinkAddress->sdl_family = AF_LINK;
  784. LinkAddress->sdl_type = IFT_ETHER;
  785. if (Information.PhysicalAddress.Domain == NetDomain80211) {
  786. LinkAddress->sdl_type = IFT_IEEE80211;
  787. }
  788. LinkAddress->sdl_nlen = NameLength;
  789. LinkAddress->sdl_alen = ETHERNET_ADDRESS_SIZE;
  790. RtlCopyMemory(LinkAddress->sdl_data,
  791. NewLinkInterface->ifa_name,
  792. NameLength);
  793. RtlCopyMemory(LLADDR(LinkAddress),
  794. Information.PhysicalAddress.Address,
  795. ETHERNET_ADDRESS_SIZE);
  796. NewLinkInterface->ifa_addr = (struct sockaddr *)LinkAddress;
  797. }
  798. CreateNetworkInterfaceAddressEnd:
  799. if (!KSUCCESS(Status)) {
  800. if (NewInterface != NULL) {
  801. ClpDestroyNetworkInterfaceAddress(NewInterface);
  802. NewInterface = NULL;
  803. }
  804. if (NewLinkInterface != NULL) {
  805. ClpDestroyNetworkInterfaceAddress(NewLinkInterface);
  806. NewLinkInterface = NULL;
  807. }
  808. }
  809. *Interface = NewInterface;
  810. *LinkInterface = NewLinkInterface;
  811. return Status;
  812. }
  813. VOID
  814. ClpDestroyNetworkInterfaceAddress (
  815. struct ifaddrs *Interface
  816. )
  817. /*++
  818. Routine Description:
  819. This routine destroys the given network interface address structure and
  820. all its resources.
  821. Arguments:
  822. Interface - Supplies a pointer to the interface to destroy.
  823. Return Value:
  824. None.
  825. --*/
  826. {
  827. if (Interface->ifa_name != NULL) {
  828. free(Interface->ifa_name);
  829. }
  830. if (Interface->ifa_addr != NULL) {
  831. free(Interface->ifa_addr);
  832. }
  833. if (Interface->ifa_netmask != NULL) {
  834. free(Interface->ifa_netmask);
  835. }
  836. if (Interface->ifa_broadaddr != NULL) {
  837. free(Interface->ifa_broadaddr);
  838. }
  839. if (Interface->ifa_dstaddr != NULL) {
  840. free(Interface->ifa_dstaddr);
  841. }
  842. if (Interface->ifa_data != NULL) {
  843. free(Interface->ifa_data);
  844. }
  845. free(Interface);
  846. return;
  847. }