|
| 1 | +package uefi |
| 2 | + |
| 3 | +import ( |
| 4 | + "unsafe" |
| 5 | +) |
| 6 | + |
| 7 | +//--------------------------------------------------------------------------- |
| 8 | +// GUIDs |
| 9 | +//--------------------------------------------------------------------------- |
| 10 | + |
| 11 | +// EFI_DHCP4_SERVICE_BINDING_PROTOCOL_GUID — §29.2.1 |
| 12 | +var EFI_DHCP4_SERVICE_BINDING_PROTOCOL_GUID = EFI_GUID{ |
| 13 | + 0x9d9a39d8, 0xbd42, 0x4a73, |
| 14 | + [8]uint8{0xa4, 0xd5, 0x8e, 0xe9, 0x4b, 0xe1, 0x13, 0x80}, |
| 15 | +} |
| 16 | + |
| 17 | +// EFI_DHCP4_PROTOCOL_GUID — §29.2.2 |
| 18 | +var EFI_DHCP4_PROTOCOL_GUID = EFI_GUID{ |
| 19 | + 0x8a219718, 0x4ef5, 0x4761, |
| 20 | + [8]uint8{0x91, 0xc8, 0xc0, 0xf0, 0x4b, 0xda, 0x9e, 0x56}, |
| 21 | +} |
| 22 | + |
| 23 | +//--------------------------------------------------------------------------- |
| 24 | +// Enums / States |
| 25 | +//--------------------------------------------------------------------------- |
| 26 | + |
| 27 | +// EFI_DHCP4_STATE — DHCP state machine §29.2.3 |
| 28 | +const ( |
| 29 | + Dhcp4Stopped = iota |
| 30 | + Dhcp4Init |
| 31 | + Dhcp4Selecting |
| 32 | + Dhcp4Requesting |
| 33 | + Dhcp4Bound |
| 34 | + Dhcp4Renewing |
| 35 | + Dhcp4Rebinding |
| 36 | + Dhcp4InitReboot |
| 37 | + Dhcp4Rebooting |
| 38 | +) |
| 39 | + |
| 40 | +// EFI_DHCP4_EVENT tracks events in the DHCP process. §29.2.4 |
| 41 | +const ( |
| 42 | + Dhcp4SendDiscover = iota + 1 |
| 43 | + Dhcp4RcvdOffer |
| 44 | + Dhcp4SelectOffer |
| 45 | + Dhcp4SendRequest |
| 46 | + Dhcp4RcvdAck |
| 47 | + Dhcp4RcvdNak |
| 48 | + Dhcp4SendDecline |
| 49 | + Dhcp4BoundCompleted |
| 50 | + Dhcp4EnterRenewing |
| 51 | + Dhcp4EnterRebinding |
| 52 | + Dhcp4AddressLost |
| 53 | + Dhcp4Fail |
| 54 | +) |
| 55 | + |
| 56 | +// EFI_DHCP4_PACKET_OPTION 29.2.4 |
| 57 | +type EFI_DHCP4_PACKET_OPTION struct { |
| 58 | + OpCode uint8 |
| 59 | + Length uint8 |
| 60 | + Data [1]uint8 |
| 61 | +} |
| 62 | + |
| 63 | +//--------------------------------------------------------------------------- |
| 64 | +// EFI_DHCP4_SERVICE_BINDING_PROTOCOL |
| 65 | +//--------------------------------------------------------------------------- |
| 66 | + |
| 67 | +type EFI_DHCP4_SERVICE_BINDING_PROTOCOL struct { |
| 68 | + createChild uintptr // (*this, *childHandle) |
| 69 | + destroyChild uintptr // (*this, childHandle) |
| 70 | +} |
| 71 | + |
| 72 | +func (p *EFI_DHCP4_SERVICE_BINDING_PROTOCOL) CreateChild(childHandle *EFI_HANDLE) EFI_STATUS { |
| 73 | + return UefiCall2( |
| 74 | + p.createChild, |
| 75 | + uintptr(unsafe.Pointer(p)), |
| 76 | + uintptr(unsafe.Pointer(childHandle)), |
| 77 | + ) |
| 78 | +} |
| 79 | + |
| 80 | +func (p *EFI_DHCP4_SERVICE_BINDING_PROTOCOL) DestroyChild(childHandle EFI_HANDLE) EFI_STATUS { |
| 81 | + return UefiCall2( |
| 82 | + p.destroyChild, |
| 83 | + uintptr(unsafe.Pointer(p)), |
| 84 | + uintptr(childHandle), |
| 85 | + ) |
| 86 | +} |
| 87 | + |
| 88 | +//--------------------------------------------------------------------------- |
| 89 | +// EFI_DHCP4_PROTOCOL |
| 90 | +//--------------------------------------------------------------------------- |
| 91 | + |
| 92 | +// EFI_DHCP4_CONFIG_DATA is for configuring a DHCP request. §29.2.4 |
| 93 | +type EFI_DHCP4_CONFIG_DATA struct { |
| 94 | + DiscoverTryCount uint32 |
| 95 | + DiscoverTimeout *uint32 |
| 96 | + RequestTryCount uint32 |
| 97 | + RequestTimeout *uint32 |
| 98 | + ClientAddress EFI_IPv4_ADDRESS |
| 99 | + Dhcp4Callback EFI_DHCP4_CALLBACK |
| 100 | + CallbackContext unsafe.Pointer // not sure about this |
| 101 | + OptionCount uint32 |
| 102 | + OptionList **EFI_DHCP4_PACKET_OPTION |
| 103 | +} |
| 104 | + |
| 105 | +// EFI_DHCP4_CALLBACK is not yet supported. Needs a PE+ -> SysV trampoline. |
| 106 | +type EFI_DHCP4_CALLBACK uintptr |
| 107 | + |
| 108 | +type EFI_DHCP4_MODE_DATA struct { |
| 109 | + State uint32 |
| 110 | + ConfigData EFI_DHCP4_CONFIG_DATA |
| 111 | + ClientAddress EFI_IPv4_ADDRESS |
| 112 | + ClientMac EFI_MAC_ADDRESS |
| 113 | + ServerAddress EFI_IPv4_ADDRESS |
| 114 | + RouterAddress EFI_IPv4_ADDRESS |
| 115 | + SubnetMask EFI_IPv4_ADDRESS |
| 116 | +} |
| 117 | + |
| 118 | +// EFI_DHCP4_PROTOCOL function table §29.2.2 |
| 119 | +type EFI_DHCP4_PROTOCOL struct { |
| 120 | + getModeData uintptr |
| 121 | + configure uintptr |
| 122 | + start uintptr |
| 123 | + renewRebind uintptr |
| 124 | + release uintptr |
| 125 | + stop uintptr |
| 126 | + build uintptr |
| 127 | + transmitReceive uintptr |
| 128 | + parse uintptr |
| 129 | +} |
| 130 | + |
| 131 | +func (p *EFI_DHCP4_PROTOCOL) GetModeData(modeData *EFI_DHCP4_MODE_DATA) EFI_STATUS { |
| 132 | + return UefiCall2( |
| 133 | + p.getModeData, |
| 134 | + uintptr(unsafe.Pointer(p)), |
| 135 | + uintptr(unsafe.Pointer(modeData)), |
| 136 | + ) |
| 137 | +} |
| 138 | + |
| 139 | +func (p *EFI_DHCP4_PROTOCOL) Configure(cfg *EFI_DHCP4_CONFIG_DATA) EFI_STATUS { |
| 140 | + return UefiCall2( |
| 141 | + p.configure, |
| 142 | + uintptr(unsafe.Pointer(p)), |
| 143 | + uintptr(unsafe.Pointer(cfg)), |
| 144 | + ) |
| 145 | +} |
| 146 | + |
| 147 | +func (p *EFI_DHCP4_PROTOCOL) Start(asyncEvent *EFI_EVENT) EFI_STATUS { |
| 148 | + return UefiCall2( |
| 149 | + p.start, |
| 150 | + uintptr(unsafe.Pointer(p)), |
| 151 | + uintptr(unsafe.Pointer(asyncEvent)), |
| 152 | + ) |
| 153 | +} |
| 154 | + |
| 155 | +func (p *EFI_DHCP4_PROTOCOL) RenewRebind(asyncEvent *EFI_EVENT) EFI_STATUS { |
| 156 | + return UefiCall2(p.renewRebind, uintptr(unsafe.Pointer(p)), uintptr(unsafe.Pointer(asyncEvent))) |
| 157 | +} |
| 158 | + |
| 159 | +func (p *EFI_DHCP4_PROTOCOL) Release(asyncEvent *EFI_EVENT) EFI_STATUS { |
| 160 | + return UefiCall2(p.release, uintptr(unsafe.Pointer(p)), uintptr(unsafe.Pointer(asyncEvent))) |
| 161 | +} |
| 162 | + |
| 163 | +func (p *EFI_DHCP4_PROTOCOL) Stop() EFI_STATUS { |
| 164 | + return UefiCall1(p.stop, uintptr(unsafe.Pointer(p))) |
| 165 | +} |
| 166 | + |
| 167 | +func (p *EFI_DHCP4_PROTOCOL) Build(packetBuffer unsafe.Pointer) EFI_STATUS { |
| 168 | + return UefiCall2(p.build, uintptr(unsafe.Pointer(p)), uintptr(packetBuffer)) |
| 169 | +} |
| 170 | + |
| 171 | +func (p *EFI_DHCP4_PROTOCOL) TransmitReceive(token unsafe.Pointer) EFI_STATUS { |
| 172 | + return UefiCall2(p.transmitReceive, uintptr(unsafe.Pointer(p)), uintptr(token)) |
| 173 | +} |
| 174 | + |
| 175 | +func (p *EFI_DHCP4_PROTOCOL) Parse(packetBuffer unsafe.Pointer, parseResult unsafe.Pointer) EFI_STATUS { |
| 176 | + return UefiCall3(p.parse, uintptr(unsafe.Pointer(p)), uintptr(packetBuffer), uintptr(parseResult)) |
| 177 | +} |
| 178 | + |
| 179 | +// DHCPv4 wraps EFI_DHCP4_PROTOCOL to provide a more go idiomatic API for handling DHCPv4. |
| 180 | +type DHCPv4 struct { |
| 181 | + *EFI_DHCP4_PROTOCOL |
| 182 | +} |
| 183 | + |
| 184 | +func EnumerateDHCPv4() ([]*DHCPv4, error) { |
| 185 | + var ( |
| 186 | + handleCount UINTN |
| 187 | + handleBuffer *EFI_HANDLE |
| 188 | + ) |
| 189 | + status := BS().LocateHandleBuffer(ByProtocol, &EFI_DHCP4_SERVICE_BINDING_PROTOCOL_GUID, nil, &handleCount, &handleBuffer) |
| 190 | + if status != EFI_SUCCESS { |
| 191 | + return nil, StatusError(status) |
| 192 | + } |
| 193 | + // if none were found, we should have gotten EFI_NOT_FOUND |
| 194 | + |
| 195 | + //turn handleBuffer into a slice of EFI_HANDLEs |
| 196 | + handleSlice := unsafe.Slice((*EFI_HANDLE)(unsafe.Pointer(handleBuffer)), int(handleCount)) |
| 197 | + |
| 198 | + dhcpv4s := make([]*DHCPv4, 0, int(handleCount)) |
| 199 | + |
| 200 | + // Turn Binding handles into Protocol |
| 201 | + for i := range handleSlice { |
| 202 | + var binding *EFI_DHCP4_SERVICE_BINDING_PROTOCOL |
| 203 | + status := BS().HandleProtocol( |
| 204 | + handleSlice[i], |
| 205 | + &EFI_DHCP4_SERVICE_BINDING_PROTOCOL_GUID, |
| 206 | + unsafe.Pointer(&binding), |
| 207 | + ) |
| 208 | + if status != EFI_SUCCESS { |
| 209 | + // just skip, or error out entirely?? Hmm.. |
| 210 | + continue |
| 211 | + } |
| 212 | + var bindChild EFI_HANDLE |
| 213 | + // TODO: track and clean up after the children |
| 214 | + status = binding.CreateChild(&bindChild) |
| 215 | + if status != EFI_SUCCESS { |
| 216 | + continue |
| 217 | + } |
| 218 | + var dhcpp *EFI_DHCP4_PROTOCOL |
| 219 | + status = BS().HandleProtocol( |
| 220 | + bindChild, |
| 221 | + &EFI_DHCP4_PROTOCOL_GUID, |
| 222 | + unsafe.Pointer(&dhcpp), |
| 223 | + ) |
| 224 | + if status != EFI_SUCCESS { |
| 225 | + continue |
| 226 | + } |
| 227 | + dhcpv4s = append(dhcpv4s, &DHCPv4{EFI_DHCP4_PROTOCOL: dhcpp}) |
| 228 | + } |
| 229 | + |
| 230 | + return dhcpv4s, nil |
| 231 | +} |
0 commit comments