interface_freebsd.odin 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. //+build freebsd
  2. package net
  3. /*
  4. Package net implements cross-platform Berkeley Sockets, DNS resolution and associated procedures.
  5. For other protocols and their features, see subdirectories of this package.
  6. */
  7. /*
  8. Copyright 2022 Tetralux <[email protected]>
  9. Copyright 2022 Colin Davidson <[email protected]>
  10. Copyright 2022 Jeroen van Rijn <[email protected]>.
  11. Copyright 2024 Feoramund <[email protected]>.
  12. Made available under Odin's BSD-3 license.
  13. List of contributors:
  14. Tetralux: Initial implementation
  15. Colin Davidson: Linux platform code, OSX platform code, Odin-native DNS resolver
  16. Jeroen van Rijn: Cross platform unification, code style, documentation
  17. Feoramund: FreeBSD platform code
  18. */
  19. import "core:c"
  20. import "core:strings"
  21. import "core:sys/freebsd"
  22. @(private)
  23. _enumerate_interfaces :: proc(allocator := context.allocator) -> (interfaces: []Network_Interface, err: Network_Error) {
  24. // This is a simplified implementation of `getifaddrs` from the FreeBSD
  25. // libc using only Odin and syscalls.
  26. context.allocator = allocator
  27. mib := [6]freebsd.MIB_Identifier {
  28. .CTL_NET,
  29. cast(freebsd.MIB_Identifier)freebsd.Protocol_Family.ROUTE,
  30. freebsd.MIB_Identifier(0),
  31. freebsd.MIB_Identifier(0),
  32. .NET_RT_IFLISTL,
  33. freebsd.MIB_Identifier(0),
  34. }
  35. // Figure out how much space we need.
  36. needed: c.size_t = ---
  37. errno := freebsd.sysctl(mib[:], nil, &needed, nil, 0)
  38. if errno != nil {
  39. return nil, .Unable_To_Enumerate_Network_Interfaces
  40. }
  41. // Allocate and get the entries.
  42. buf, alloc_err := make([]byte, needed)
  43. if alloc_err != nil {
  44. return nil, .Unable_To_Enumerate_Network_Interfaces
  45. }
  46. defer delete(buf)
  47. errno = freebsd.sysctl(mib[:], &buf[0], &needed, nil, 0)
  48. if errno != nil {
  49. return nil, .Unable_To_Enumerate_Network_Interfaces
  50. }
  51. // Build the interfaces with each message.
  52. if_builder: [dynamic]Network_Interface
  53. for message_pointer: uintptr = 0; message_pointer < cast(uintptr)needed; /**/ {
  54. rtm := cast(^freebsd.Route_Message_Header)&buf[message_pointer]
  55. if rtm.version != freebsd.RTM_VERSION {
  56. continue
  57. }
  58. #partial switch rtm.type {
  59. case .IFINFO:
  60. ifm := cast(^freebsd.Interface_Message_Header_Len)&buf[message_pointer]
  61. if .IFP not_in ifm.addrs {
  62. // No name available.
  63. break
  64. }
  65. dl := cast(^freebsd.Socket_Address_Data_Link)&buf[message_pointer + cast(uintptr)ifm.len]
  66. if_data := cast(^freebsd.Interface_Data)&buf[message_pointer + cast(uintptr)ifm.data_off]
  67. // This is done this way so the different message types can
  68. // dynamically build a `Network_Interface`.
  69. resize(&if_builder, max(len(if_builder), 1 + cast(int)ifm.index))
  70. interface := if_builder[ifm.index]
  71. interface.adapter_name = strings.clone_from_bytes(dl.data[0:dl.nlen])
  72. interface.mtu = if_data.mtu
  73. switch if_data.link_state {
  74. case .UNKNOWN: /* Do nothing; the default value is valid. */
  75. case .UP: interface.link.state |= { .Up }
  76. case .DOWN: interface.link.state |= { .Down }
  77. }
  78. // TODO: Uncertain if these are equivalent:
  79. // interface.link.transmit_speed = if_data.baudrate
  80. // interface.link.receive_speed = if_data.baudrate
  81. if dl.type == .LOOP {
  82. interface.link.state |= { .Loopback }
  83. } else {
  84. interface.physical_address = physical_address_to_string(dl.data[dl.nlen:][:6])
  85. }
  86. if_builder[ifm.index] = interface
  87. case .NEWADDR:
  88. RTA_MASKS :: freebsd.Route_Address_Flags { .IFA, .NETMASK }
  89. ifam := cast(^freebsd.Interface_Address_Message_Header_Len)&buf[message_pointer]
  90. if ifam.addrs & RTA_MASKS == {} {
  91. break
  92. }
  93. resize(&if_builder, max(len(if_builder), 1 + cast(int)ifam.index))
  94. interface := if_builder[ifam.index]
  95. address_pointer := message_pointer + cast(uintptr)ifam.len
  96. lease: Lease
  97. address_set: bool
  98. for address_type in ifam.addrs {
  99. ptr := cast(^freebsd.Socket_Address_Basic)&buf[address_pointer]
  100. #partial switch address_type {
  101. case .IFA:
  102. #partial switch ptr.family {
  103. case .INET:
  104. real := cast(^freebsd.Socket_Address_Internet)ptr
  105. lease.address = cast(IP4_Address)real.addr.addr8
  106. address_set = true
  107. case .INET6:
  108. real := cast(^freebsd.Socket_Address_Internet6)ptr
  109. lease.address = cast(IP6_Address)real.addr.addr16
  110. address_set = true
  111. }
  112. case .NETMASK:
  113. #partial switch ptr.family {
  114. case .INET:
  115. real := cast(^freebsd.Socket_Address_Internet)ptr
  116. lease.netmask = cast(Netmask)cast(IP4_Address)real.addr.addr8
  117. case .INET6:
  118. real := cast(^freebsd.Socket_Address_Internet6)ptr
  119. lease.netmask = cast(Netmask)cast(IP6_Address)real.addr.addr16
  120. }
  121. }
  122. SALIGN : u8 : size_of(c.long) - 1
  123. address_advance: uintptr = ---
  124. if ptr.len > 0 {
  125. address_advance = cast(uintptr)((ptr.len + SALIGN) & ~SALIGN)
  126. } else {
  127. address_advance = cast(uintptr)(SALIGN + 1)
  128. }
  129. address_pointer += address_advance
  130. }
  131. if address_set {
  132. append(&interface.unicast, lease)
  133. }
  134. if_builder[ifam.index] = interface
  135. }
  136. message_pointer += cast(uintptr)rtm.msglen
  137. }
  138. // Remove any interfaces that were allocated but had no name.
  139. #no_bounds_check for i := len(if_builder) - 1; i >= 0; i -= 1 {
  140. if len(if_builder[i].adapter_name) == 0 {
  141. ordered_remove(&if_builder, i)
  142. }
  143. }
  144. return if_builder[:], nil
  145. }