1da4961c7SRebecca Cran /*- 2da4961c7SRebecca Cran * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3da4961c7SRebecca Cran * 4da4961c7SRebecca Cran * Copyright (c) 2019 Intel Corporation 5da4961c7SRebecca Cran * 6da4961c7SRebecca Cran * Redistribution and use in source and binary forms, with or without 7da4961c7SRebecca Cran * modification, are permitted provided that the following conditions 8da4961c7SRebecca Cran * are met: 9da4961c7SRebecca Cran * 1. Redistributions of source code must retain the above copyright 10da4961c7SRebecca Cran * notice, this list of conditions and the following disclaimer. 11da4961c7SRebecca Cran * 2. Redistributions in binary form must reproduce the above copyright 12da4961c7SRebecca Cran * notice, this list of conditions and the following disclaimer in the 13da4961c7SRebecca Cran * documentation and/or other materials provided with the distribution. 14da4961c7SRebecca Cran * 15da4961c7SRebecca Cran * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 16da4961c7SRebecca Cran * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17da4961c7SRebecca Cran * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18da4961c7SRebecca Cran * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 19da4961c7SRebecca Cran * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20da4961c7SRebecca Cran * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21da4961c7SRebecca Cran * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22da4961c7SRebecca Cran * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23da4961c7SRebecca Cran * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24da4961c7SRebecca Cran * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25da4961c7SRebecca Cran * SUCH DAMAGE. 26da4961c7SRebecca Cran * 27da4961c7SRebecca Cran * $FreeBSD$ 28da4961c7SRebecca Cran */ 29da4961c7SRebecca Cran 30da4961c7SRebecca Cran #include <sys/cdefs.h> 31da4961c7SRebecca Cran __FBSDID("$FreeBSD$"); 32da4961c7SRebecca Cran 33da4961c7SRebecca Cran #include <sys/types.h> 34da4961c7SRebecca Cran 35da4961c7SRebecca Cran #include <netinet/in.h> 36da4961c7SRebecca Cran #include <netinet/in_systm.h> 37da4961c7SRebecca Cran 38da4961c7SRebecca Cran #include <stand.h> 39da4961c7SRebecca Cran #include <net.h> 40da4961c7SRebecca Cran 41da4961c7SRebecca Cran #include <efi.h> 42da4961c7SRebecca Cran #include <efilib.h> 43da4961c7SRebecca Cran #include <efiprot.h> 44da4961c7SRebecca Cran #include <Protocol/Http.h> 45da4961c7SRebecca Cran #include <Protocol/Ip4Config2.h> 46da4961c7SRebecca Cran #include <Protocol/ServiceBinding.h> 47da4961c7SRebecca Cran 48da4961c7SRebecca Cran /* Poll timeout in milliseconds */ 49da4961c7SRebecca Cran static const int EFIHTTP_POLL_TIMEOUT = 300000; 50da4961c7SRebecca Cran 51da4961c7SRebecca Cran static EFI_GUID http_guid = EFI_HTTP_PROTOCOL_GUID; 52da4961c7SRebecca Cran static EFI_GUID httpsb_guid = EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID; 53da4961c7SRebecca Cran static EFI_GUID ip4config2_guid = EFI_IP4_CONFIG2_PROTOCOL_GUID; 54da4961c7SRebecca Cran 551ee03da2SRebecca Cran static bool efihttp_init_done = false; 561ee03da2SRebecca Cran 57da4961c7SRebecca Cran static int efihttp_dev_init(void); 58da4961c7SRebecca Cran static int efihttp_dev_strategy(void *devdata, int rw, daddr_t blk, size_t size, 59da4961c7SRebecca Cran char *buf, size_t *rsize); 60da4961c7SRebecca Cran static int efihttp_dev_open(struct open_file *f, ...); 61da4961c7SRebecca Cran static int efihttp_dev_close(struct open_file *f); 62da4961c7SRebecca Cran 63da4961c7SRebecca Cran static int efihttp_fs_open(const char *path, struct open_file *f); 64da4961c7SRebecca Cran static int efihttp_fs_close(struct open_file *f); 65da4961c7SRebecca Cran static int efihttp_fs_read(struct open_file *f, void *buf, size_t size, 66da4961c7SRebecca Cran size_t *resid); 67da4961c7SRebecca Cran static int efihttp_fs_write(struct open_file *f, const void *buf, size_t size, 68da4961c7SRebecca Cran size_t *resid); 69da4961c7SRebecca Cran static off_t efihttp_fs_seek(struct open_file *f, off_t offset, int where); 70da4961c7SRebecca Cran static int efihttp_fs_stat(struct open_file *f, struct stat *sb); 71da4961c7SRebecca Cran static int efihttp_fs_readdir(struct open_file *f, struct dirent *d); 72da4961c7SRebecca Cran 73da4961c7SRebecca Cran struct open_efihttp { 74da4961c7SRebecca Cran EFI_HTTP_PROTOCOL *http; 75da4961c7SRebecca Cran EFI_HANDLE http_handle; 76da4961c7SRebecca Cran EFI_HANDLE dev_handle; 77da4961c7SRebecca Cran char *uri_base; 78da4961c7SRebecca Cran }; 79da4961c7SRebecca Cran 80da4961c7SRebecca Cran struct file_efihttp { 81da4961c7SRebecca Cran ssize_t size; 82da4961c7SRebecca Cran off_t offset; 83da4961c7SRebecca Cran char *path; 84da4961c7SRebecca Cran bool is_dir; 85da4961c7SRebecca Cran }; 86da4961c7SRebecca Cran 87da4961c7SRebecca Cran struct devsw efihttp_dev = { 88da4961c7SRebecca Cran .dv_name = "http", 89da4961c7SRebecca Cran .dv_type = DEVT_NET, 90da4961c7SRebecca Cran .dv_init = efihttp_dev_init, 91da4961c7SRebecca Cran .dv_strategy = efihttp_dev_strategy, 92da4961c7SRebecca Cran .dv_open = efihttp_dev_open, 93da4961c7SRebecca Cran .dv_close = efihttp_dev_close, 94da4961c7SRebecca Cran .dv_ioctl = noioctl, 95da4961c7SRebecca Cran .dv_print = NULL, 96da4961c7SRebecca Cran .dv_cleanup = NULL, 97da4961c7SRebecca Cran }; 98da4961c7SRebecca Cran 99da4961c7SRebecca Cran struct fs_ops efihttp_fsops = { 100da4961c7SRebecca Cran .fs_name = "efihttp", 101da4961c7SRebecca Cran .fo_open = efihttp_fs_open, 102da4961c7SRebecca Cran .fo_close = efihttp_fs_close, 103da4961c7SRebecca Cran .fo_read = efihttp_fs_read, 104da4961c7SRebecca Cran .fo_write = efihttp_fs_write, 105da4961c7SRebecca Cran .fo_seek = efihttp_fs_seek, 106da4961c7SRebecca Cran .fo_stat = efihttp_fs_stat, 107da4961c7SRebecca Cran .fo_readdir = efihttp_fs_readdir, 108da4961c7SRebecca Cran }; 109da4961c7SRebecca Cran 110da4961c7SRebecca Cran static void EFIAPI 1118136db28SToomas Soome notify(EFI_EVENT event __unused, void *context) 112da4961c7SRebecca Cran { 113da4961c7SRebecca Cran bool *b; 114da4961c7SRebecca Cran 115da4961c7SRebecca Cran b = (bool *)context; 116da4961c7SRebecca Cran *b = true; 117da4961c7SRebecca Cran } 118da4961c7SRebecca Cran 119da4961c7SRebecca Cran static int 120da4961c7SRebecca Cran setup_ipv4_config2(EFI_HANDLE handle, MAC_ADDR_DEVICE_PATH *mac, 121da4961c7SRebecca Cran IPv4_DEVICE_PATH *ipv4, DNS_DEVICE_PATH *dns) 122da4961c7SRebecca Cran { 123da4961c7SRebecca Cran EFI_IP4_CONFIG2_PROTOCOL *ip4config2; 124da4961c7SRebecca Cran EFI_STATUS status; 125da4961c7SRebecca Cran 126da4961c7SRebecca Cran status = BS->OpenProtocol(handle, &ip4config2_guid, 127da4961c7SRebecca Cran (void **)&ip4config2, IH, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); 128da4961c7SRebecca Cran if (EFI_ERROR(status)) 129da4961c7SRebecca Cran return (efi_status_to_errno(status)); 130*21b2840eSToomas Soome if (ipv4 != NULL) { 131*21b2840eSToomas Soome if (mac != NULL) { 132da4961c7SRebecca Cran setenv("boot.netif.hwaddr", 133da4961c7SRebecca Cran ether_sprintf((u_char *)mac->MacAddress.Addr), 1); 134*21b2840eSToomas Soome } 135da4961c7SRebecca Cran setenv("boot.netif.ip", 136da4961c7SRebecca Cran inet_ntoa(*(struct in_addr *)ipv4->LocalIpAddress.Addr), 1); 137da4961c7SRebecca Cran setenv("boot.netif.netmask", 138da4961c7SRebecca Cran intoa(*(n_long *)ipv4->SubnetMask.Addr), 1); 139da4961c7SRebecca Cran setenv("boot.netif.gateway", 140da4961c7SRebecca Cran inet_ntoa(*(struct in_addr *)ipv4->GatewayIpAddress.Addr), 141da4961c7SRebecca Cran 1); 142da4961c7SRebecca Cran status = ip4config2->SetData(ip4config2, 143da4961c7SRebecca Cran Ip4Config2DataTypePolicy, sizeof(EFI_IP4_CONFIG2_POLICY), 144da4961c7SRebecca Cran &(EFI_IP4_CONFIG2_POLICY) { Ip4Config2PolicyStatic }); 145da4961c7SRebecca Cran if (EFI_ERROR(status)) 146da4961c7SRebecca Cran return (efi_status_to_errno(status)); 147da4961c7SRebecca Cran 148da4961c7SRebecca Cran status = ip4config2->SetData(ip4config2, 149da4961c7SRebecca Cran Ip4Config2DataTypeManualAddress, 150da4961c7SRebecca Cran sizeof(EFI_IP4_CONFIG2_MANUAL_ADDRESS), 151da4961c7SRebecca Cran &(EFI_IP4_CONFIG2_MANUAL_ADDRESS) { 152da4961c7SRebecca Cran .Address = ipv4->LocalIpAddress, 153da4961c7SRebecca Cran .SubnetMask = ipv4->SubnetMask }); 154da4961c7SRebecca Cran if (EFI_ERROR(status)) 155da4961c7SRebecca Cran return (efi_status_to_errno(status)); 156da4961c7SRebecca Cran 157da4961c7SRebecca Cran if (ipv4->GatewayIpAddress.Addr[0] != 0) { 158da4961c7SRebecca Cran status = ip4config2->SetData(ip4config2, 159da4961c7SRebecca Cran Ip4Config2DataTypeGateway, sizeof(EFI_IPv4_ADDRESS), 160da4961c7SRebecca Cran &ipv4->GatewayIpAddress); 161da4961c7SRebecca Cran if (EFI_ERROR(status)) 162da4961c7SRebecca Cran return (efi_status_to_errno(status)); 163da4961c7SRebecca Cran } 164da4961c7SRebecca Cran 165*21b2840eSToomas Soome if (dns != NULL) { 166da4961c7SRebecca Cran status = ip4config2->SetData(ip4config2, 167da4961c7SRebecca Cran Ip4Config2DataTypeDnsServer, 168da4961c7SRebecca Cran sizeof(EFI_IPv4_ADDRESS), &dns->DnsServerIp); 169da4961c7SRebecca Cran if (EFI_ERROR(status)) 170da4961c7SRebecca Cran return (efi_status_to_errno(status)); 171da4961c7SRebecca Cran } 172da4961c7SRebecca Cran } else { 173da4961c7SRebecca Cran status = ip4config2->SetData(ip4config2, 174da4961c7SRebecca Cran Ip4Config2DataTypePolicy, sizeof(EFI_IP4_CONFIG2_POLICY), 175da4961c7SRebecca Cran &(EFI_IP4_CONFIG2_POLICY) { Ip4Config2PolicyDhcp }); 176da4961c7SRebecca Cran if (EFI_ERROR(status)) 177da4961c7SRebecca Cran return (efi_status_to_errno(status)); 178da4961c7SRebecca Cran } 179da4961c7SRebecca Cran 180da4961c7SRebecca Cran return (0); 181da4961c7SRebecca Cran } 182da4961c7SRebecca Cran 183da4961c7SRebecca Cran static int 184da4961c7SRebecca Cran efihttp_dev_init(void) 185da4961c7SRebecca Cran { 186da4961c7SRebecca Cran EFI_DEVICE_PATH *imgpath, *devpath; 187da4961c7SRebecca Cran URI_DEVICE_PATH *uri; 188da4961c7SRebecca Cran EFI_HANDLE handle; 189da4961c7SRebecca Cran EFI_STATUS status; 190da4961c7SRebecca Cran int err; 191da4961c7SRebecca Cran bool found_http; 192da4961c7SRebecca Cran 193da4961c7SRebecca Cran imgpath = efi_lookup_image_devpath(IH); 194da4961c7SRebecca Cran if (imgpath == NULL) 195da4961c7SRebecca Cran return (ENXIO); 196da4961c7SRebecca Cran devpath = imgpath; 197da4961c7SRebecca Cran found_http = false; 198da4961c7SRebecca Cran for (; !IsDevicePathEnd(devpath); 199da4961c7SRebecca Cran devpath = NextDevicePathNode(devpath)) { 200da4961c7SRebecca Cran if (DevicePathType(devpath) != MESSAGING_DEVICE_PATH || 201da4961c7SRebecca Cran DevicePathSubType(devpath) != MSG_URI_DP) 202da4961c7SRebecca Cran continue; 203da4961c7SRebecca Cran uri = (URI_DEVICE_PATH *)devpath; 2045bca29b8SToomas Soome if (strncmp("http", (const char *)uri->Uri, 4) == 0) 205da4961c7SRebecca Cran found_http = true; 206da4961c7SRebecca Cran } 207da4961c7SRebecca Cran if (!found_http) 208da4961c7SRebecca Cran return (ENXIO); 209da4961c7SRebecca Cran 210da4961c7SRebecca Cran status = BS->LocateDevicePath(&httpsb_guid, &imgpath, &handle); 211da4961c7SRebecca Cran if (EFI_ERROR(status)) 212da4961c7SRebecca Cran return (efi_status_to_errno(status)); 213da4961c7SRebecca Cran 214da4961c7SRebecca Cran err = efi_register_handles(&efihttp_dev, &handle, NULL, 1); 2151ee03da2SRebecca Cran if (!err) 2161ee03da2SRebecca Cran efihttp_init_done = true; 2171ee03da2SRebecca Cran 218da4961c7SRebecca Cran return (err); 219da4961c7SRebecca Cran } 220da4961c7SRebecca Cran 221da4961c7SRebecca Cran static int 2228136db28SToomas Soome efihttp_dev_strategy(void *devdata __unused, int rw __unused, 2238136db28SToomas Soome daddr_t blk __unused, size_t size __unused, char *buf __unused, 2248136db28SToomas Soome size_t *rsize __unused) 225da4961c7SRebecca Cran { 226da4961c7SRebecca Cran return (EIO); 227da4961c7SRebecca Cran } 228da4961c7SRebecca Cran 229da4961c7SRebecca Cran static int 230da4961c7SRebecca Cran efihttp_dev_open(struct open_file *f, ...) 231da4961c7SRebecca Cran { 232da4961c7SRebecca Cran EFI_HTTP_CONFIG_DATA config; 233da4961c7SRebecca Cran EFI_HTTPv4_ACCESS_POINT config_access; 234da4961c7SRebecca Cran DNS_DEVICE_PATH *dns; 235da4961c7SRebecca Cran EFI_DEVICE_PATH *devpath, *imgpath; 236da4961c7SRebecca Cran EFI_SERVICE_BINDING_PROTOCOL *sb; 237da4961c7SRebecca Cran IPv4_DEVICE_PATH *ipv4; 238da4961c7SRebecca Cran MAC_ADDR_DEVICE_PATH *mac; 239da4961c7SRebecca Cran URI_DEVICE_PATH *uri; 240da4961c7SRebecca Cran struct devdesc *dev; 241da4961c7SRebecca Cran struct open_efihttp *oh; 242da4961c7SRebecca Cran char *c; 243da4961c7SRebecca Cran EFI_HANDLE handle; 244da4961c7SRebecca Cran EFI_STATUS status; 245da4961c7SRebecca Cran int err, len; 246da4961c7SRebecca Cran 2471ee03da2SRebecca Cran if (!efihttp_init_done) 2481ee03da2SRebecca Cran return (ENXIO); 2491ee03da2SRebecca Cran 250da4961c7SRebecca Cran imgpath = efi_lookup_image_devpath(IH); 251da4961c7SRebecca Cran if (imgpath == NULL) 252da4961c7SRebecca Cran return (ENXIO); 253da4961c7SRebecca Cran devpath = imgpath; 254da4961c7SRebecca Cran status = BS->LocateDevicePath(&httpsb_guid, &devpath, &handle); 255da4961c7SRebecca Cran if (EFI_ERROR(status)) 256da4961c7SRebecca Cran return (efi_status_to_errno(status)); 257*21b2840eSToomas Soome mac = NULL; 258da4961c7SRebecca Cran ipv4 = NULL; 259da4961c7SRebecca Cran dns = NULL; 260da4961c7SRebecca Cran uri = NULL; 261da4961c7SRebecca Cran for (; !IsDevicePathEnd(imgpath); 262da4961c7SRebecca Cran imgpath = NextDevicePathNode(imgpath)) { 263da4961c7SRebecca Cran if (DevicePathType(imgpath) != MESSAGING_DEVICE_PATH) 264da4961c7SRebecca Cran continue; 265da4961c7SRebecca Cran switch (DevicePathSubType(imgpath)) { 266da4961c7SRebecca Cran case MSG_MAC_ADDR_DP: 267da4961c7SRebecca Cran mac = (MAC_ADDR_DEVICE_PATH *)imgpath; 268da4961c7SRebecca Cran break; 269da4961c7SRebecca Cran case MSG_IPv4_DP: 270da4961c7SRebecca Cran ipv4 = (IPv4_DEVICE_PATH *)imgpath; 271da4961c7SRebecca Cran break; 272da4961c7SRebecca Cran case MSG_DNS_DP: 273da4961c7SRebecca Cran dns = (DNS_DEVICE_PATH *)imgpath; 274da4961c7SRebecca Cran break; 275da4961c7SRebecca Cran case MSG_URI_DP: 276da4961c7SRebecca Cran uri = (URI_DEVICE_PATH *)imgpath; 277da4961c7SRebecca Cran break; 278da4961c7SRebecca Cran default: 279da4961c7SRebecca Cran break; 280da4961c7SRebecca Cran } 281da4961c7SRebecca Cran } 282da4961c7SRebecca Cran 283da4961c7SRebecca Cran if (uri == NULL) 284da4961c7SRebecca Cran return (ENXIO); 285da4961c7SRebecca Cran 286da4961c7SRebecca Cran err = setup_ipv4_config2(handle, mac, ipv4, dns); 287da4961c7SRebecca Cran if (err) 288da4961c7SRebecca Cran return (err); 289da4961c7SRebecca Cran 290da4961c7SRebecca Cran oh = calloc(1, sizeof(struct open_efihttp)); 291da4961c7SRebecca Cran if (!oh) 292da4961c7SRebecca Cran return (ENOMEM); 293da4961c7SRebecca Cran oh->dev_handle = handle; 294da4961c7SRebecca Cran dev = (struct devdesc *)f->f_devdata; 295da4961c7SRebecca Cran dev->d_opendata = oh; 296da4961c7SRebecca Cran 297da4961c7SRebecca Cran status = BS->OpenProtocol(handle, &httpsb_guid, (void **)&sb, IH, NULL, 298da4961c7SRebecca Cran EFI_OPEN_PROTOCOL_GET_PROTOCOL); 299da4961c7SRebecca Cran if (EFI_ERROR(status)) { 300da4961c7SRebecca Cran err = efi_status_to_errno(status); 301da4961c7SRebecca Cran goto end; 302da4961c7SRebecca Cran } 303da4961c7SRebecca Cran 304da4961c7SRebecca Cran status = sb->CreateChild(sb, &oh->http_handle); 305da4961c7SRebecca Cran if (EFI_ERROR(status)) { 306da4961c7SRebecca Cran err = efi_status_to_errno(status); 307da4961c7SRebecca Cran goto end; 308da4961c7SRebecca Cran } 309da4961c7SRebecca Cran 310da4961c7SRebecca Cran status = BS->OpenProtocol(oh->http_handle, &http_guid, 311da4961c7SRebecca Cran (void **)&oh->http, IH, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); 312da4961c7SRebecca Cran if (EFI_ERROR(status)) { 313da4961c7SRebecca Cran sb->DestroyChild(sb, oh->http_handle); 314da4961c7SRebecca Cran err = efi_status_to_errno(status); 315da4961c7SRebecca Cran goto end; 316da4961c7SRebecca Cran } 317da4961c7SRebecca Cran 318da4961c7SRebecca Cran config.HttpVersion = HttpVersion11; 319da4961c7SRebecca Cran config.TimeOutMillisec = 0; 320da4961c7SRebecca Cran config.LocalAddressIsIPv6 = FALSE; 321da4961c7SRebecca Cran config.AccessPoint.IPv4Node = &config_access; 322da4961c7SRebecca Cran config_access.UseDefaultAddress = TRUE; 323da4961c7SRebecca Cran config_access.LocalPort = 0; 324da4961c7SRebecca Cran status = oh->http->Configure(oh->http, &config); 325da4961c7SRebecca Cran if (EFI_ERROR(status)) { 326da4961c7SRebecca Cran sb->DestroyChild(sb, oh->http_handle); 327da4961c7SRebecca Cran err = efi_status_to_errno(status); 328da4961c7SRebecca Cran goto end; 329da4961c7SRebecca Cran } 330da4961c7SRebecca Cran 331da4961c7SRebecca Cran /* 332da4961c7SRebecca Cran * Here we make attempt to construct a "base" URI by stripping 333da4961c7SRebecca Cran * the last two path components from the loaded URI under the 334da4961c7SRebecca Cran * assumption that it is something like: 335da4961c7SRebecca Cran * 336da4961c7SRebecca Cran * http://127.0.0.1/foo/boot/loader.efi 337da4961c7SRebecca Cran * 338da4961c7SRebecca Cran * hoping to arriving at: 339da4961c7SRebecca Cran * 340da4961c7SRebecca Cran * http://127.0.0.1/foo/ 341da4961c7SRebecca Cran */ 342da4961c7SRebecca Cran len = DevicePathNodeLength(&uri->Header) - sizeof(URI_DEVICE_PATH); 343da4961c7SRebecca Cran oh->uri_base = malloc(len + 1); 344da4961c7SRebecca Cran if (oh->uri_base == NULL) { 345da4961c7SRebecca Cran err = ENOMEM; 346da4961c7SRebecca Cran goto end; 347da4961c7SRebecca Cran } 3485bca29b8SToomas Soome strncpy(oh->uri_base, (const char *)uri->Uri, len); 349da4961c7SRebecca Cran oh->uri_base[len] = '\0'; 350da4961c7SRebecca Cran c = strrchr(oh->uri_base, '/'); 351da4961c7SRebecca Cran if (c != NULL) 352da4961c7SRebecca Cran *c = '\0'; 353da4961c7SRebecca Cran c = strrchr(oh->uri_base, '/'); 354da4961c7SRebecca Cran if (c != NULL && *(c + 1) != '\0') 355da4961c7SRebecca Cran *(c + 1) = '\0'; 356da4961c7SRebecca Cran 357da4961c7SRebecca Cran err = 0; 358da4961c7SRebecca Cran end: 359da4961c7SRebecca Cran if (err != 0) { 360da4961c7SRebecca Cran free(dev->d_opendata); 361da4961c7SRebecca Cran dev->d_opendata = NULL; 362da4961c7SRebecca Cran } 363da4961c7SRebecca Cran return (err); 364da4961c7SRebecca Cran } 365da4961c7SRebecca Cran 366da4961c7SRebecca Cran static int 367da4961c7SRebecca Cran efihttp_dev_close(struct open_file *f) 368da4961c7SRebecca Cran { 369da4961c7SRebecca Cran EFI_SERVICE_BINDING_PROTOCOL *sb; 370da4961c7SRebecca Cran struct devdesc *dev; 371da4961c7SRebecca Cran struct open_efihttp *oh; 372da4961c7SRebecca Cran EFI_STATUS status; 373da4961c7SRebecca Cran 374da4961c7SRebecca Cran dev = (struct devdesc *)f->f_devdata; 375da4961c7SRebecca Cran oh = (struct open_efihttp *)dev->d_opendata; 376da4961c7SRebecca Cran status = BS->OpenProtocol(oh->dev_handle, &httpsb_guid, (void **)&sb, 377da4961c7SRebecca Cran IH, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); 378da4961c7SRebecca Cran if (EFI_ERROR(status)) 379da4961c7SRebecca Cran return (efi_status_to_errno(status)); 380da4961c7SRebecca Cran sb->DestroyChild(sb, oh->http_handle); 381da4961c7SRebecca Cran free(oh->uri_base); 382da4961c7SRebecca Cran free(oh); 383da4961c7SRebecca Cran dev->d_opendata = NULL; 384da4961c7SRebecca Cran return (0); 385da4961c7SRebecca Cran } 386da4961c7SRebecca Cran 387da4961c7SRebecca Cran static int 388da4961c7SRebecca Cran _efihttp_fs_open(const char *path, struct open_file *f) 389da4961c7SRebecca Cran { 390da4961c7SRebecca Cran EFI_HTTP_CONFIG_DATA config; 391da4961c7SRebecca Cran EFI_HTTPv4_ACCESS_POINT config_access; 392da4961c7SRebecca Cran EFI_HTTP_TOKEN token; 393da4961c7SRebecca Cran EFI_HTTP_MESSAGE message; 394da4961c7SRebecca Cran EFI_HTTP_REQUEST_DATA request; 395da4961c7SRebecca Cran EFI_HTTP_RESPONSE_DATA response; 396da4961c7SRebecca Cran EFI_HTTP_HEADER headers[3]; 397da4961c7SRebecca Cran char *host, *hostp; 398da4961c7SRebecca Cran char *c; 399da4961c7SRebecca Cran struct devdesc *dev; 400da4961c7SRebecca Cran struct open_efihttp *oh; 401da4961c7SRebecca Cran struct file_efihttp *fh; 402da4961c7SRebecca Cran EFI_STATUS status; 403f7ae06cbSToomas Soome UINTN i; 404da4961c7SRebecca Cran int polltime; 405da4961c7SRebecca Cran bool done; 406da4961c7SRebecca Cran 407da4961c7SRebecca Cran dev = (struct devdesc *)f->f_devdata; 408da4961c7SRebecca Cran oh = (struct open_efihttp *)dev->d_opendata; 409da4961c7SRebecca Cran fh = calloc(1, sizeof(struct file_efihttp)); 410da4961c7SRebecca Cran if (fh == NULL) 411da4961c7SRebecca Cran return (ENOMEM); 412da4961c7SRebecca Cran f->f_fsdata = fh; 413da4961c7SRebecca Cran fh->path = strdup(path); 414da4961c7SRebecca Cran 415da4961c7SRebecca Cran /* 416da4961c7SRebecca Cran * Reset the HTTP state. 417da4961c7SRebecca Cran * 418da4961c7SRebecca Cran * EDK II's persistent HTTP connection handling is graceless, 419da4961c7SRebecca Cran * assuming that all connections are persistent regardless of 420da4961c7SRebecca Cran * any Connection: header or HTTP version reported by the 421da4961c7SRebecca Cran * server, and failing to send requests when a more sane 422da4961c7SRebecca Cran * implementation would seem to be just reestablishing the 423da4961c7SRebecca Cran * closed connection. 424da4961c7SRebecca Cran * 425da4961c7SRebecca Cran * In the hopes of having some robustness, we indicate to the 426da4961c7SRebecca Cran * server that we will close the connection by using a 427da4961c7SRebecca Cran * Connection: close header. And then here we manually 428da4961c7SRebecca Cran * unconfigure and reconfigure the http instance to force the 429da4961c7SRebecca Cran * connection closed. 430da4961c7SRebecca Cran */ 431da4961c7SRebecca Cran memset(&config, 0, sizeof(config)); 432da4961c7SRebecca Cran memset(&config_access, 0, sizeof(config_access)); 433da4961c7SRebecca Cran config.AccessPoint.IPv4Node = &config_access; 434da4961c7SRebecca Cran status = oh->http->GetModeData(oh->http, &config); 435da4961c7SRebecca Cran if (EFI_ERROR(status)) 436da4961c7SRebecca Cran return (efi_status_to_errno(status)); 437da4961c7SRebecca Cran status = oh->http->Configure(oh->http, NULL); 438da4961c7SRebecca Cran if (EFI_ERROR(status)) 439da4961c7SRebecca Cran return (efi_status_to_errno(status)); 440da4961c7SRebecca Cran status = oh->http->Configure(oh->http, &config); 441da4961c7SRebecca Cran if (EFI_ERROR(status)) 442da4961c7SRebecca Cran return (efi_status_to_errno(status)); 443da4961c7SRebecca Cran 444da4961c7SRebecca Cran /* Send the read request */ 445da4961c7SRebecca Cran done = false; 446da4961c7SRebecca Cran status = BS->CreateEvent(EVT_NOTIFY_SIGNAL, TPL_CALLBACK, notify, 447da4961c7SRebecca Cran &done, &token.Event); 448da4961c7SRebecca Cran if (EFI_ERROR(status)) 449da4961c7SRebecca Cran return (efi_status_to_errno(status)); 450da4961c7SRebecca Cran 451da4961c7SRebecca Cran /* extract the host portion of the URL */ 452da4961c7SRebecca Cran host = strdup(oh->uri_base); 453da4961c7SRebecca Cran if (host == NULL) 454da4961c7SRebecca Cran return (ENOMEM); 455da4961c7SRebecca Cran hostp = host; 456da4961c7SRebecca Cran /* Remove the protocol scheme */ 457da4961c7SRebecca Cran c = strchr(host, '/'); 458da4961c7SRebecca Cran if (c != NULL && *(c + 1) == '/') 459da4961c7SRebecca Cran hostp = (c + 2); 460da4961c7SRebecca Cran 461da4961c7SRebecca Cran /* Remove any path information */ 462da4961c7SRebecca Cran c = strchr(hostp, '/'); 463da4961c7SRebecca Cran if (c != NULL) 464da4961c7SRebecca Cran *c = '\0'; 465da4961c7SRebecca Cran 466da4961c7SRebecca Cran token.Status = EFI_NOT_READY; 467da4961c7SRebecca Cran token.Message = &message; 468da4961c7SRebecca Cran message.Data.Request = &request; 469da4961c7SRebecca Cran message.HeaderCount = 3; 470da4961c7SRebecca Cran message.Headers = headers; 471da4961c7SRebecca Cran message.BodyLength = 0; 472da4961c7SRebecca Cran message.Body = NULL; 473da4961c7SRebecca Cran request.Method = HttpMethodGet; 474da4961c7SRebecca Cran request.Url = calloc(strlen(oh->uri_base) + strlen(path) + 1, 2); 4755bca29b8SToomas Soome headers[0].FieldName = (CHAR8 *)"Host"; 4765bca29b8SToomas Soome headers[0].FieldValue = (CHAR8 *)hostp; 4775bca29b8SToomas Soome headers[1].FieldName = (CHAR8 *)"Connection"; 4785bca29b8SToomas Soome headers[1].FieldValue = (CHAR8 *)"close"; 4795bca29b8SToomas Soome headers[2].FieldName = (CHAR8 *)"Accept"; 4805bca29b8SToomas Soome headers[2].FieldValue = (CHAR8 *)"*/*"; 481da4961c7SRebecca Cran cpy8to16(oh->uri_base, request.Url, strlen(oh->uri_base)); 482da4961c7SRebecca Cran cpy8to16(path, request.Url + strlen(oh->uri_base), strlen(path)); 483da4961c7SRebecca Cran status = oh->http->Request(oh->http, &token); 484da4961c7SRebecca Cran free(request.Url); 485da4961c7SRebecca Cran free(host); 486da4961c7SRebecca Cran if (EFI_ERROR(status)) { 487da4961c7SRebecca Cran BS->CloseEvent(token.Event); 488da4961c7SRebecca Cran return (efi_status_to_errno(status)); 489da4961c7SRebecca Cran } 490da4961c7SRebecca Cran 491da4961c7SRebecca Cran polltime = 0; 492da4961c7SRebecca Cran while (!done && polltime < EFIHTTP_POLL_TIMEOUT) { 493da4961c7SRebecca Cran status = oh->http->Poll(oh->http); 494da4961c7SRebecca Cran if (EFI_ERROR(status)) 495da4961c7SRebecca Cran break; 496da4961c7SRebecca Cran 497da4961c7SRebecca Cran if (!done) { 498da4961c7SRebecca Cran delay(100 * 1000); 499da4961c7SRebecca Cran polltime += 100; 500da4961c7SRebecca Cran } 501da4961c7SRebecca Cran } 502da4961c7SRebecca Cran BS->CloseEvent(token.Event); 503da4961c7SRebecca Cran if (EFI_ERROR(token.Status)) 504da4961c7SRebecca Cran return (efi_status_to_errno(token.Status)); 505da4961c7SRebecca Cran 506da4961c7SRebecca Cran /* Wait for the read response */ 507da4961c7SRebecca Cran done = false; 508da4961c7SRebecca Cran status = BS->CreateEvent(EVT_NOTIFY_SIGNAL, TPL_CALLBACK, notify, 509da4961c7SRebecca Cran &done, &token.Event); 510da4961c7SRebecca Cran if (EFI_ERROR(status)) 511da4961c7SRebecca Cran return (efi_status_to_errno(status)); 512da4961c7SRebecca Cran token.Status = EFI_NOT_READY; 513da4961c7SRebecca Cran token.Message = &message; 514da4961c7SRebecca Cran message.Data.Response = &response; 515da4961c7SRebecca Cran message.HeaderCount = 0; 516da4961c7SRebecca Cran message.Headers = NULL; 517da4961c7SRebecca Cran message.BodyLength = 0; 518da4961c7SRebecca Cran message.Body = NULL; 519da4961c7SRebecca Cran response.StatusCode = HTTP_STATUS_UNSUPPORTED_STATUS; 520da4961c7SRebecca Cran status = oh->http->Response(oh->http, &token); 521da4961c7SRebecca Cran if (EFI_ERROR(status)) { 522da4961c7SRebecca Cran BS->CloseEvent(token.Event); 523da4961c7SRebecca Cran return (efi_status_to_errno(status)); 524da4961c7SRebecca Cran } 525da4961c7SRebecca Cran 526da4961c7SRebecca Cran polltime = 0; 527da4961c7SRebecca Cran while (!done && polltime < EFIHTTP_POLL_TIMEOUT) { 528da4961c7SRebecca Cran status = oh->http->Poll(oh->http); 529da4961c7SRebecca Cran if (EFI_ERROR(status)) 530da4961c7SRebecca Cran break; 531da4961c7SRebecca Cran 532da4961c7SRebecca Cran if (!done) { 533da4961c7SRebecca Cran delay(100 * 1000); 534da4961c7SRebecca Cran polltime += 100; 535da4961c7SRebecca Cran } 536da4961c7SRebecca Cran } 537da4961c7SRebecca Cran BS->CloseEvent(token.Event); 538da4961c7SRebecca Cran if (EFI_ERROR(token.Status)) { 539da4961c7SRebecca Cran BS->FreePool(message.Headers); 540da4961c7SRebecca Cran return (efi_status_to_errno(token.Status)); 541da4961c7SRebecca Cran } 542da4961c7SRebecca Cran if (response.StatusCode != HTTP_STATUS_200_OK) { 543da4961c7SRebecca Cran BS->FreePool(message.Headers); 544da4961c7SRebecca Cran return (EIO); 545da4961c7SRebecca Cran } 546da4961c7SRebecca Cran fh->size = 0; 547da4961c7SRebecca Cran fh->is_dir = false; 548da4961c7SRebecca Cran for (i = 0; i < message.HeaderCount; i++) { 5495bca29b8SToomas Soome if (strcasecmp((const char *)message.Headers[i].FieldName, 550da4961c7SRebecca Cran "Content-Length") == 0) 5515bca29b8SToomas Soome fh->size = strtoul((const char *) 5525bca29b8SToomas Soome message.Headers[i].FieldValue, NULL, 10); 5535bca29b8SToomas Soome else if (strcasecmp((const char *)message.Headers[i].FieldName, 554da4961c7SRebecca Cran "Content-type") == 0) { 5555bca29b8SToomas Soome if (strncmp((const char *)message.Headers[i].FieldValue, 5565bca29b8SToomas Soome "text/html", 9) == 0) 557da4961c7SRebecca Cran fh->is_dir = true; 558da4961c7SRebecca Cran } 559da4961c7SRebecca Cran } 560da4961c7SRebecca Cran 561da4961c7SRebecca Cran return (0); 562da4961c7SRebecca Cran } 563da4961c7SRebecca Cran 564da4961c7SRebecca Cran static int 565da4961c7SRebecca Cran efihttp_fs_open(const char *path, struct open_file *f) 566da4961c7SRebecca Cran { 567da4961c7SRebecca Cran char *path_slash; 568da4961c7SRebecca Cran int err; 569da4961c7SRebecca Cran 5701ee03da2SRebecca Cran if (!efihttp_init_done) 5711ee03da2SRebecca Cran return (ENXIO); 572da4961c7SRebecca Cran /* 573da4961c7SRebecca Cran * If any path fails to open, try with a trailing slash in 574da4961c7SRebecca Cran * case it's a directory. 575da4961c7SRebecca Cran */ 576da4961c7SRebecca Cran err = _efihttp_fs_open(path, f); 577da4961c7SRebecca Cran if (err != 0) { 578da4961c7SRebecca Cran path_slash = malloc(strlen(path) + 2); 579da4961c7SRebecca Cran if (path_slash == NULL) 580da4961c7SRebecca Cran return (ENOMEM); 581da4961c7SRebecca Cran strcpy(path_slash, path); 582da4961c7SRebecca Cran strcat(path_slash, "/"); 583da4961c7SRebecca Cran err = _efihttp_fs_open(path_slash, f); 584da4961c7SRebecca Cran free(path_slash); 585da4961c7SRebecca Cran } 586da4961c7SRebecca Cran return (err); 587da4961c7SRebecca Cran } 588da4961c7SRebecca Cran 589da4961c7SRebecca Cran static int 5908136db28SToomas Soome efihttp_fs_close(struct open_file *f __unused) 591da4961c7SRebecca Cran { 592da4961c7SRebecca Cran return (0); 593da4961c7SRebecca Cran } 594da4961c7SRebecca Cran 595da4961c7SRebecca Cran static int 596da4961c7SRebecca Cran _efihttp_fs_read(struct open_file *f, void *buf, size_t size, size_t *resid) 597da4961c7SRebecca Cran { 598da4961c7SRebecca Cran EFI_HTTP_TOKEN token; 599da4961c7SRebecca Cran EFI_HTTP_MESSAGE message; 600da4961c7SRebecca Cran EFI_STATUS status; 601da4961c7SRebecca Cran struct devdesc *dev; 602da4961c7SRebecca Cran struct open_efihttp *oh; 603da4961c7SRebecca Cran struct file_efihttp *fh; 604da4961c7SRebecca Cran bool done; 605da4961c7SRebecca Cran int polltime; 606da4961c7SRebecca Cran 607da4961c7SRebecca Cran fh = (struct file_efihttp *)f->f_fsdata; 608da4961c7SRebecca Cran 609da4961c7SRebecca Cran if (fh->size > 0 && fh->offset >= fh->size) { 610da4961c7SRebecca Cran if (resid != NULL) 611da4961c7SRebecca Cran *resid = size; 612da4961c7SRebecca Cran 613da4961c7SRebecca Cran return 0; 614da4961c7SRebecca Cran } 615da4961c7SRebecca Cran 616da4961c7SRebecca Cran dev = (struct devdesc *)f->f_devdata; 617da4961c7SRebecca Cran oh = (struct open_efihttp *)dev->d_opendata; 618da4961c7SRebecca Cran done = false; 619da4961c7SRebecca Cran status = BS->CreateEvent(EVT_NOTIFY_SIGNAL, TPL_CALLBACK, notify, 620da4961c7SRebecca Cran &done, &token.Event); 621da4961c7SRebecca Cran if (EFI_ERROR(status)) { 622da4961c7SRebecca Cran return (efi_status_to_errno(status)); 623da4961c7SRebecca Cran } 624da4961c7SRebecca Cran token.Status = EFI_NOT_READY; 625da4961c7SRebecca Cran token.Message = &message; 626da4961c7SRebecca Cran message.Data.Request = NULL; 627da4961c7SRebecca Cran message.HeaderCount = 0; 628da4961c7SRebecca Cran message.Headers = NULL; 629da4961c7SRebecca Cran message.BodyLength = size; 630da4961c7SRebecca Cran message.Body = buf; 631da4961c7SRebecca Cran status = oh->http->Response(oh->http, &token); 632da4961c7SRebecca Cran if (status == EFI_CONNECTION_FIN) { 633da4961c7SRebecca Cran if (resid) 634da4961c7SRebecca Cran *resid = size; 635da4961c7SRebecca Cran return (0); 636da4961c7SRebecca Cran } else if (EFI_ERROR(status)) { 637da4961c7SRebecca Cran BS->CloseEvent(token.Event); 638da4961c7SRebecca Cran return (efi_status_to_errno(status)); 639da4961c7SRebecca Cran } 640da4961c7SRebecca Cran polltime = 0; 641da4961c7SRebecca Cran while (!done && polltime < EFIHTTP_POLL_TIMEOUT) { 642da4961c7SRebecca Cran status = oh->http->Poll(oh->http); 643da4961c7SRebecca Cran if (EFI_ERROR(status)) 644da4961c7SRebecca Cran break; 645da4961c7SRebecca Cran 646da4961c7SRebecca Cran if (!done) { 647da4961c7SRebecca Cran delay(100 * 1000); 648da4961c7SRebecca Cran polltime += 100; 649da4961c7SRebecca Cran } 650da4961c7SRebecca Cran } 651da4961c7SRebecca Cran BS->CloseEvent(token.Event); 652da4961c7SRebecca Cran if (token.Status == EFI_CONNECTION_FIN) { 653da4961c7SRebecca Cran if (resid) 654da4961c7SRebecca Cran *resid = size; 655da4961c7SRebecca Cran return (0); 656da4961c7SRebecca Cran } else if (EFI_ERROR(token.Status)) 657da4961c7SRebecca Cran return (efi_status_to_errno(token.Status)); 658da4961c7SRebecca Cran if (resid) 659da4961c7SRebecca Cran *resid = size - message.BodyLength; 660da4961c7SRebecca Cran fh->offset += message.BodyLength; 661da4961c7SRebecca Cran return (0); 662da4961c7SRebecca Cran } 663da4961c7SRebecca Cran 664da4961c7SRebecca Cran static int 665da4961c7SRebecca Cran efihttp_fs_read(struct open_file *f, void *buf, size_t size, size_t *resid) 666da4961c7SRebecca Cran { 667da4961c7SRebecca Cran size_t res; 668*21b2840eSToomas Soome int err = 0; 669da4961c7SRebecca Cran 670da4961c7SRebecca Cran while (size > 0) { 671da4961c7SRebecca Cran err = _efihttp_fs_read(f, buf, size, &res); 672da4961c7SRebecca Cran if (err != 0 || res == size) 673da4961c7SRebecca Cran goto end; 674da4961c7SRebecca Cran buf += (size - res); 675da4961c7SRebecca Cran size = res; 676da4961c7SRebecca Cran } 677da4961c7SRebecca Cran end: 678da4961c7SRebecca Cran if (resid) 679da4961c7SRebecca Cran *resid = size; 680da4961c7SRebecca Cran return (err); 681da4961c7SRebecca Cran } 682da4961c7SRebecca Cran 683da4961c7SRebecca Cran static int 6848136db28SToomas Soome efihttp_fs_write(struct open_file *f __unused, const void *buf __unused, 6858136db28SToomas Soome size_t size __unused, size_t *resid __unused) 686da4961c7SRebecca Cran { 687da4961c7SRebecca Cran return (EIO); 688da4961c7SRebecca Cran } 689da4961c7SRebecca Cran 690da4961c7SRebecca Cran static off_t 691da4961c7SRebecca Cran efihttp_fs_seek(struct open_file *f, off_t offset, int where) 692da4961c7SRebecca Cran { 693da4961c7SRebecca Cran struct file_efihttp *fh; 694da4961c7SRebecca Cran char *path; 695da4961c7SRebecca Cran void *buf; 696da4961c7SRebecca Cran size_t res, res2; 697da4961c7SRebecca Cran int err; 698da4961c7SRebecca Cran 699da4961c7SRebecca Cran fh = (struct file_efihttp *)f->f_fsdata; 700da4961c7SRebecca Cran if (where == SEEK_SET && fh->offset == offset) 701da4961c7SRebecca Cran return (0); 702da4961c7SRebecca Cran if (where == SEEK_SET && fh->offset < offset) { 703da4961c7SRebecca Cran buf = malloc(1500); 704da4961c7SRebecca Cran res = offset - fh->offset; 705da4961c7SRebecca Cran while (res > 0) { 706da4961c7SRebecca Cran err = _efihttp_fs_read(f, buf, min(1500, res), &res2); 707da4961c7SRebecca Cran if (err != 0) { 708da4961c7SRebecca Cran free(buf); 709da4961c7SRebecca Cran return (err); 710da4961c7SRebecca Cran } 711da4961c7SRebecca Cran res -= min(1500, res) - res2; 712da4961c7SRebecca Cran } 713da4961c7SRebecca Cran free(buf); 714da4961c7SRebecca Cran return (0); 715da4961c7SRebecca Cran } else if (where == SEEK_SET) { 716da4961c7SRebecca Cran path = fh->path; 717da4961c7SRebecca Cran fh->path = NULL; 718da4961c7SRebecca Cran efihttp_fs_close(f); 719da4961c7SRebecca Cran err = efihttp_fs_open(path, f); 720da4961c7SRebecca Cran free(path); 721da4961c7SRebecca Cran if (err != 0) 722da4961c7SRebecca Cran return (err); 723da4961c7SRebecca Cran return efihttp_fs_seek(f, offset, where); 724da4961c7SRebecca Cran } 725da4961c7SRebecca Cran return (EIO); 726da4961c7SRebecca Cran } 727da4961c7SRebecca Cran 728da4961c7SRebecca Cran static int 729da4961c7SRebecca Cran efihttp_fs_stat(struct open_file *f, struct stat *sb) 730da4961c7SRebecca Cran { 731da4961c7SRebecca Cran struct file_efihttp *fh; 732da4961c7SRebecca Cran 733da4961c7SRebecca Cran fh = (struct file_efihttp *)f->f_fsdata; 734da4961c7SRebecca Cran memset(sb, 0, sizeof(*sb)); 735da4961c7SRebecca Cran sb->st_nlink = 1; 736da4961c7SRebecca Cran sb->st_mode = 0777 | (fh->is_dir ? S_IFDIR : S_IFREG); 737da4961c7SRebecca Cran sb->st_size = fh->size; 738da4961c7SRebecca Cran return (0); 739da4961c7SRebecca Cran } 740da4961c7SRebecca Cran 741da4961c7SRebecca Cran static int 742da4961c7SRebecca Cran efihttp_fs_readdir(struct open_file *f, struct dirent *d) 743da4961c7SRebecca Cran { 744da4961c7SRebecca Cran static char *dirbuf = NULL, *db2, *cursor; 745da4961c7SRebecca Cran static int dirbuf_len = 0; 746da4961c7SRebecca Cran char *end; 747da4961c7SRebecca Cran struct file_efihttp *fh; 748da4961c7SRebecca Cran 749da4961c7SRebecca Cran fh = (struct file_efihttp *)f->f_fsdata; 750da4961c7SRebecca Cran if (dirbuf_len < fh->size) { 751da4961c7SRebecca Cran db2 = realloc(dirbuf, fh->size); 752da4961c7SRebecca Cran if (db2 == NULL) { 753da4961c7SRebecca Cran free(dirbuf); 754da4961c7SRebecca Cran return (ENOMEM); 755da4961c7SRebecca Cran } else 756da4961c7SRebecca Cran dirbuf = db2; 757da4961c7SRebecca Cran 758da4961c7SRebecca Cran dirbuf_len = fh->size; 759da4961c7SRebecca Cran } 760da4961c7SRebecca Cran 761da4961c7SRebecca Cran if (fh->offset != fh->size) { 762da4961c7SRebecca Cran efihttp_fs_seek(f, 0, SEEK_SET); 763da4961c7SRebecca Cran efihttp_fs_read(f, dirbuf, dirbuf_len, NULL); 764da4961c7SRebecca Cran cursor = dirbuf; 765da4961c7SRebecca Cran } 766da4961c7SRebecca Cran 767da4961c7SRebecca Cran cursor = strstr(cursor, "<a href=\""); 768da4961c7SRebecca Cran if (cursor == NULL) 769da4961c7SRebecca Cran return (ENOENT); 770da4961c7SRebecca Cran cursor += 9; 771da4961c7SRebecca Cran end = strchr(cursor, '"'); 772da4961c7SRebecca Cran if (*(end - 1) == '/') { 773da4961c7SRebecca Cran end--; 774da4961c7SRebecca Cran d->d_type = DT_DIR; 775da4961c7SRebecca Cran } else 776da4961c7SRebecca Cran d->d_type = DT_REG; 777da4961c7SRebecca Cran memcpy(d->d_name, cursor, end - cursor); 778da4961c7SRebecca Cran d->d_name[end - cursor] = '\0'; 779da4961c7SRebecca Cran 780da4961c7SRebecca Cran return (0); 781da4961c7SRebecca Cran } 782