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 111da4961c7SRebecca Cran notify(EFI_EVENT event, 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)); 130da4961c7SRebecca Cran if (ipv4) { 131da4961c7SRebecca Cran setenv("boot.netif.hwaddr", 132da4961c7SRebecca Cran ether_sprintf((u_char *)mac->MacAddress.Addr), 1); 133da4961c7SRebecca Cran setenv("boot.netif.ip", 134da4961c7SRebecca Cran inet_ntoa(*(struct in_addr *)ipv4->LocalIpAddress.Addr), 1); 135da4961c7SRebecca Cran setenv("boot.netif.netmask", 136da4961c7SRebecca Cran intoa(*(n_long *)ipv4->SubnetMask.Addr), 1); 137da4961c7SRebecca Cran setenv("boot.netif.gateway", 138da4961c7SRebecca Cran inet_ntoa(*(struct in_addr *)ipv4->GatewayIpAddress.Addr), 139da4961c7SRebecca Cran 1); 140da4961c7SRebecca Cran status = ip4config2->SetData(ip4config2, 141da4961c7SRebecca Cran Ip4Config2DataTypePolicy, sizeof(EFI_IP4_CONFIG2_POLICY), 142da4961c7SRebecca Cran &(EFI_IP4_CONFIG2_POLICY) { Ip4Config2PolicyStatic }); 143da4961c7SRebecca Cran if (EFI_ERROR(status)) 144da4961c7SRebecca Cran return (efi_status_to_errno(status)); 145da4961c7SRebecca Cran 146da4961c7SRebecca Cran status = ip4config2->SetData(ip4config2, 147da4961c7SRebecca Cran Ip4Config2DataTypeManualAddress, 148da4961c7SRebecca Cran sizeof(EFI_IP4_CONFIG2_MANUAL_ADDRESS), 149da4961c7SRebecca Cran &(EFI_IP4_CONFIG2_MANUAL_ADDRESS) { 150da4961c7SRebecca Cran .Address = ipv4->LocalIpAddress, 151da4961c7SRebecca Cran .SubnetMask = ipv4->SubnetMask }); 152da4961c7SRebecca Cran if (EFI_ERROR(status)) 153da4961c7SRebecca Cran return (efi_status_to_errno(status)); 154da4961c7SRebecca Cran 155da4961c7SRebecca Cran if (ipv4->GatewayIpAddress.Addr[0] != 0) { 156da4961c7SRebecca Cran status = ip4config2->SetData(ip4config2, 157da4961c7SRebecca Cran Ip4Config2DataTypeGateway, sizeof(EFI_IPv4_ADDRESS), 158da4961c7SRebecca Cran &ipv4->GatewayIpAddress); 159da4961c7SRebecca Cran if (EFI_ERROR(status)) 160da4961c7SRebecca Cran return (efi_status_to_errno(status)); 161da4961c7SRebecca Cran } 162da4961c7SRebecca Cran 163da4961c7SRebecca Cran if (dns) { 164da4961c7SRebecca Cran status = ip4config2->SetData(ip4config2, 165da4961c7SRebecca Cran Ip4Config2DataTypeDnsServer, 166da4961c7SRebecca Cran sizeof(EFI_IPv4_ADDRESS), &dns->DnsServerIp); 167da4961c7SRebecca Cran if (EFI_ERROR(status)) 168da4961c7SRebecca Cran return (efi_status_to_errno(status)); 169da4961c7SRebecca Cran } 170da4961c7SRebecca Cran } else { 171da4961c7SRebecca Cran status = ip4config2->SetData(ip4config2, 172da4961c7SRebecca Cran Ip4Config2DataTypePolicy, sizeof(EFI_IP4_CONFIG2_POLICY), 173da4961c7SRebecca Cran &(EFI_IP4_CONFIG2_POLICY) { Ip4Config2PolicyDhcp }); 174da4961c7SRebecca Cran if (EFI_ERROR(status)) 175da4961c7SRebecca Cran return (efi_status_to_errno(status)); 176da4961c7SRebecca Cran } 177da4961c7SRebecca Cran 178da4961c7SRebecca Cran return (0); 179da4961c7SRebecca Cran } 180da4961c7SRebecca Cran 181da4961c7SRebecca Cran static int 182da4961c7SRebecca Cran efihttp_dev_init(void) 183da4961c7SRebecca Cran { 184da4961c7SRebecca Cran EFI_DEVICE_PATH *imgpath, *devpath; 185da4961c7SRebecca Cran URI_DEVICE_PATH *uri; 186da4961c7SRebecca Cran EFI_HANDLE handle; 187da4961c7SRebecca Cran EFI_STATUS status; 188da4961c7SRebecca Cran int err; 189da4961c7SRebecca Cran bool found_http; 190da4961c7SRebecca Cran 191da4961c7SRebecca Cran imgpath = efi_lookup_image_devpath(IH); 192da4961c7SRebecca Cran if (imgpath == NULL) 193da4961c7SRebecca Cran return (ENXIO); 194da4961c7SRebecca Cran devpath = imgpath; 195da4961c7SRebecca Cran found_http = false; 196da4961c7SRebecca Cran for (; !IsDevicePathEnd(devpath); 197da4961c7SRebecca Cran devpath = NextDevicePathNode(devpath)) { 198da4961c7SRebecca Cran if (DevicePathType(devpath) != MESSAGING_DEVICE_PATH || 199da4961c7SRebecca Cran DevicePathSubType(devpath) != MSG_URI_DP) 200da4961c7SRebecca Cran continue; 201da4961c7SRebecca Cran uri = (URI_DEVICE_PATH *)devpath; 202*5bca29b8SToomas Soome if (strncmp("http", (const char *)uri->Uri, 4) == 0) 203da4961c7SRebecca Cran found_http = true; 204da4961c7SRebecca Cran } 205da4961c7SRebecca Cran if (!found_http) 206da4961c7SRebecca Cran return (ENXIO); 207da4961c7SRebecca Cran 208da4961c7SRebecca Cran status = BS->LocateDevicePath(&httpsb_guid, &imgpath, &handle); 209da4961c7SRebecca Cran if (EFI_ERROR(status)) 210da4961c7SRebecca Cran return (efi_status_to_errno(status)); 211da4961c7SRebecca Cran 212da4961c7SRebecca Cran err = efi_register_handles(&efihttp_dev, &handle, NULL, 1); 2131ee03da2SRebecca Cran if (!err) 2141ee03da2SRebecca Cran efihttp_init_done = true; 2151ee03da2SRebecca Cran 216da4961c7SRebecca Cran return (err); 217da4961c7SRebecca Cran } 218da4961c7SRebecca Cran 219da4961c7SRebecca Cran static int 220da4961c7SRebecca Cran efihttp_dev_strategy(void *devdata, int rw, daddr_t blk, size_t size, char *buf, 221da4961c7SRebecca Cran size_t *rsize) 222da4961c7SRebecca Cran { 223da4961c7SRebecca Cran return (EIO); 224da4961c7SRebecca Cran } 225da4961c7SRebecca Cran 226da4961c7SRebecca Cran static int 227da4961c7SRebecca Cran efihttp_dev_open(struct open_file *f, ...) 228da4961c7SRebecca Cran { 229da4961c7SRebecca Cran EFI_HTTP_CONFIG_DATA config; 230da4961c7SRebecca Cran EFI_HTTPv4_ACCESS_POINT config_access; 231da4961c7SRebecca Cran DNS_DEVICE_PATH *dns; 232da4961c7SRebecca Cran EFI_DEVICE_PATH *devpath, *imgpath; 233da4961c7SRebecca Cran EFI_SERVICE_BINDING_PROTOCOL *sb; 234da4961c7SRebecca Cran IPv4_DEVICE_PATH *ipv4; 235da4961c7SRebecca Cran MAC_ADDR_DEVICE_PATH *mac; 236da4961c7SRebecca Cran URI_DEVICE_PATH *uri; 237da4961c7SRebecca Cran struct devdesc *dev; 238da4961c7SRebecca Cran struct open_efihttp *oh; 239da4961c7SRebecca Cran char *c; 240da4961c7SRebecca Cran EFI_HANDLE handle; 241da4961c7SRebecca Cran EFI_STATUS status; 242da4961c7SRebecca Cran int err, len; 243da4961c7SRebecca Cran 2441ee03da2SRebecca Cran if (!efihttp_init_done) 2451ee03da2SRebecca Cran return (ENXIO); 2461ee03da2SRebecca Cran 247da4961c7SRebecca Cran imgpath = efi_lookup_image_devpath(IH); 248da4961c7SRebecca Cran if (imgpath == NULL) 249da4961c7SRebecca Cran return (ENXIO); 250da4961c7SRebecca Cran devpath = imgpath; 251da4961c7SRebecca Cran status = BS->LocateDevicePath(&httpsb_guid, &devpath, &handle); 252da4961c7SRebecca Cran if (EFI_ERROR(status)) 253da4961c7SRebecca Cran return (efi_status_to_errno(status)); 254da4961c7SRebecca Cran ipv4 = NULL; 255da4961c7SRebecca Cran dns = NULL; 256da4961c7SRebecca Cran uri = NULL; 257da4961c7SRebecca Cran for (; !IsDevicePathEnd(imgpath); 258da4961c7SRebecca Cran imgpath = NextDevicePathNode(imgpath)) { 259da4961c7SRebecca Cran if (DevicePathType(imgpath) != MESSAGING_DEVICE_PATH) 260da4961c7SRebecca Cran continue; 261da4961c7SRebecca Cran switch (DevicePathSubType(imgpath)) { 262da4961c7SRebecca Cran case MSG_MAC_ADDR_DP: 263da4961c7SRebecca Cran mac = (MAC_ADDR_DEVICE_PATH *)imgpath; 264da4961c7SRebecca Cran break; 265da4961c7SRebecca Cran case MSG_IPv4_DP: 266da4961c7SRebecca Cran ipv4 = (IPv4_DEVICE_PATH *)imgpath; 267da4961c7SRebecca Cran break; 268da4961c7SRebecca Cran case MSG_DNS_DP: 269da4961c7SRebecca Cran dns = (DNS_DEVICE_PATH *)imgpath; 270da4961c7SRebecca Cran break; 271da4961c7SRebecca Cran case MSG_URI_DP: 272da4961c7SRebecca Cran uri = (URI_DEVICE_PATH *)imgpath; 273da4961c7SRebecca Cran break; 274da4961c7SRebecca Cran default: 275da4961c7SRebecca Cran break; 276da4961c7SRebecca Cran } 277da4961c7SRebecca Cran } 278da4961c7SRebecca Cran 279da4961c7SRebecca Cran if (uri == NULL) 280da4961c7SRebecca Cran return (ENXIO); 281da4961c7SRebecca Cran 282da4961c7SRebecca Cran err = setup_ipv4_config2(handle, mac, ipv4, dns); 283da4961c7SRebecca Cran if (err) 284da4961c7SRebecca Cran return (err); 285da4961c7SRebecca Cran 286da4961c7SRebecca Cran oh = calloc(1, sizeof(struct open_efihttp)); 287da4961c7SRebecca Cran if (!oh) 288da4961c7SRebecca Cran return (ENOMEM); 289da4961c7SRebecca Cran oh->dev_handle = handle; 290da4961c7SRebecca Cran dev = (struct devdesc *)f->f_devdata; 291da4961c7SRebecca Cran dev->d_opendata = oh; 292da4961c7SRebecca Cran 293da4961c7SRebecca Cran status = BS->OpenProtocol(handle, &httpsb_guid, (void **)&sb, IH, NULL, 294da4961c7SRebecca Cran EFI_OPEN_PROTOCOL_GET_PROTOCOL); 295da4961c7SRebecca Cran if (EFI_ERROR(status)) { 296da4961c7SRebecca Cran err = efi_status_to_errno(status); 297da4961c7SRebecca Cran goto end; 298da4961c7SRebecca Cran } 299da4961c7SRebecca Cran 300da4961c7SRebecca Cran status = sb->CreateChild(sb, &oh->http_handle); 301da4961c7SRebecca Cran if (EFI_ERROR(status)) { 302da4961c7SRebecca Cran err = efi_status_to_errno(status); 303da4961c7SRebecca Cran goto end; 304da4961c7SRebecca Cran } 305da4961c7SRebecca Cran 306da4961c7SRebecca Cran status = BS->OpenProtocol(oh->http_handle, &http_guid, 307da4961c7SRebecca Cran (void **)&oh->http, IH, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); 308da4961c7SRebecca Cran if (EFI_ERROR(status)) { 309da4961c7SRebecca Cran sb->DestroyChild(sb, oh->http_handle); 310da4961c7SRebecca Cran err = efi_status_to_errno(status); 311da4961c7SRebecca Cran goto end; 312da4961c7SRebecca Cran } 313da4961c7SRebecca Cran 314da4961c7SRebecca Cran config.HttpVersion = HttpVersion11; 315da4961c7SRebecca Cran config.TimeOutMillisec = 0; 316da4961c7SRebecca Cran config.LocalAddressIsIPv6 = FALSE; 317da4961c7SRebecca Cran config.AccessPoint.IPv4Node = &config_access; 318da4961c7SRebecca Cran config_access.UseDefaultAddress = TRUE; 319da4961c7SRebecca Cran config_access.LocalPort = 0; 320da4961c7SRebecca Cran status = oh->http->Configure(oh->http, &config); 321da4961c7SRebecca Cran if (EFI_ERROR(status)) { 322da4961c7SRebecca Cran sb->DestroyChild(sb, oh->http_handle); 323da4961c7SRebecca Cran err = efi_status_to_errno(status); 324da4961c7SRebecca Cran goto end; 325da4961c7SRebecca Cran } 326da4961c7SRebecca Cran 327da4961c7SRebecca Cran /* 328da4961c7SRebecca Cran * Here we make attempt to construct a "base" URI by stripping 329da4961c7SRebecca Cran * the last two path components from the loaded URI under the 330da4961c7SRebecca Cran * assumption that it is something like: 331da4961c7SRebecca Cran * 332da4961c7SRebecca Cran * http://127.0.0.1/foo/boot/loader.efi 333da4961c7SRebecca Cran * 334da4961c7SRebecca Cran * hoping to arriving at: 335da4961c7SRebecca Cran * 336da4961c7SRebecca Cran * http://127.0.0.1/foo/ 337da4961c7SRebecca Cran */ 338da4961c7SRebecca Cran len = DevicePathNodeLength(&uri->Header) - sizeof(URI_DEVICE_PATH); 339da4961c7SRebecca Cran oh->uri_base = malloc(len + 1); 340da4961c7SRebecca Cran if (oh->uri_base == NULL) { 341da4961c7SRebecca Cran err = ENOMEM; 342da4961c7SRebecca Cran goto end; 343da4961c7SRebecca Cran } 344*5bca29b8SToomas Soome strncpy(oh->uri_base, (const char *)uri->Uri, len); 345da4961c7SRebecca Cran oh->uri_base[len] = '\0'; 346da4961c7SRebecca Cran c = strrchr(oh->uri_base, '/'); 347da4961c7SRebecca Cran if (c != NULL) 348da4961c7SRebecca Cran *c = '\0'; 349da4961c7SRebecca Cran c = strrchr(oh->uri_base, '/'); 350da4961c7SRebecca Cran if (c != NULL && *(c + 1) != '\0') 351da4961c7SRebecca Cran *(c + 1) = '\0'; 352da4961c7SRebecca Cran 353da4961c7SRebecca Cran err = 0; 354da4961c7SRebecca Cran end: 355da4961c7SRebecca Cran if (err != 0) { 356da4961c7SRebecca Cran free(dev->d_opendata); 357da4961c7SRebecca Cran dev->d_opendata = NULL; 358da4961c7SRebecca Cran } 359da4961c7SRebecca Cran return (err); 360da4961c7SRebecca Cran } 361da4961c7SRebecca Cran 362da4961c7SRebecca Cran static int 363da4961c7SRebecca Cran efihttp_dev_close(struct open_file *f) 364da4961c7SRebecca Cran { 365da4961c7SRebecca Cran EFI_SERVICE_BINDING_PROTOCOL *sb; 366da4961c7SRebecca Cran struct devdesc *dev; 367da4961c7SRebecca Cran struct open_efihttp *oh; 368da4961c7SRebecca Cran EFI_STATUS status; 369da4961c7SRebecca Cran 370da4961c7SRebecca Cran dev = (struct devdesc *)f->f_devdata; 371da4961c7SRebecca Cran oh = (struct open_efihttp *)dev->d_opendata; 372da4961c7SRebecca Cran status = BS->OpenProtocol(oh->dev_handle, &httpsb_guid, (void **)&sb, 373da4961c7SRebecca Cran IH, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); 374da4961c7SRebecca Cran if (EFI_ERROR(status)) 375da4961c7SRebecca Cran return (efi_status_to_errno(status)); 376da4961c7SRebecca Cran sb->DestroyChild(sb, oh->http_handle); 377da4961c7SRebecca Cran free(oh->uri_base); 378da4961c7SRebecca Cran free(oh); 379da4961c7SRebecca Cran dev->d_opendata = NULL; 380da4961c7SRebecca Cran return (0); 381da4961c7SRebecca Cran } 382da4961c7SRebecca Cran 383da4961c7SRebecca Cran static int 384da4961c7SRebecca Cran _efihttp_fs_open(const char *path, struct open_file *f) 385da4961c7SRebecca Cran { 386da4961c7SRebecca Cran EFI_HTTP_CONFIG_DATA config; 387da4961c7SRebecca Cran EFI_HTTPv4_ACCESS_POINT config_access; 388da4961c7SRebecca Cran EFI_HTTP_TOKEN token; 389da4961c7SRebecca Cran EFI_HTTP_MESSAGE message; 390da4961c7SRebecca Cran EFI_HTTP_REQUEST_DATA request; 391da4961c7SRebecca Cran EFI_HTTP_RESPONSE_DATA response; 392da4961c7SRebecca Cran EFI_HTTP_HEADER headers[3]; 393da4961c7SRebecca Cran char *host, *hostp; 394da4961c7SRebecca Cran char *c; 395da4961c7SRebecca Cran struct devdesc *dev; 396da4961c7SRebecca Cran struct open_efihttp *oh; 397da4961c7SRebecca Cran struct file_efihttp *fh; 398da4961c7SRebecca Cran EFI_STATUS status; 399da4961c7SRebecca Cran int i; 400da4961c7SRebecca Cran int polltime; 401da4961c7SRebecca Cran bool done; 402da4961c7SRebecca Cran 403da4961c7SRebecca Cran dev = (struct devdesc *)f->f_devdata; 404da4961c7SRebecca Cran oh = (struct open_efihttp *)dev->d_opendata; 405da4961c7SRebecca Cran fh = calloc(1, sizeof(struct file_efihttp)); 406da4961c7SRebecca Cran if (fh == NULL) 407da4961c7SRebecca Cran return (ENOMEM); 408da4961c7SRebecca Cran f->f_fsdata = fh; 409da4961c7SRebecca Cran fh->path = strdup(path); 410da4961c7SRebecca Cran 411da4961c7SRebecca Cran /* 412da4961c7SRebecca Cran * Reset the HTTP state. 413da4961c7SRebecca Cran * 414da4961c7SRebecca Cran * EDK II's persistent HTTP connection handling is graceless, 415da4961c7SRebecca Cran * assuming that all connections are persistent regardless of 416da4961c7SRebecca Cran * any Connection: header or HTTP version reported by the 417da4961c7SRebecca Cran * server, and failing to send requests when a more sane 418da4961c7SRebecca Cran * implementation would seem to be just reestablishing the 419da4961c7SRebecca Cran * closed connection. 420da4961c7SRebecca Cran * 421da4961c7SRebecca Cran * In the hopes of having some robustness, we indicate to the 422da4961c7SRebecca Cran * server that we will close the connection by using a 423da4961c7SRebecca Cran * Connection: close header. And then here we manually 424da4961c7SRebecca Cran * unconfigure and reconfigure the http instance to force the 425da4961c7SRebecca Cran * connection closed. 426da4961c7SRebecca Cran */ 427da4961c7SRebecca Cran memset(&config, 0, sizeof(config)); 428da4961c7SRebecca Cran memset(&config_access, 0, sizeof(config_access)); 429da4961c7SRebecca Cran config.AccessPoint.IPv4Node = &config_access; 430da4961c7SRebecca Cran status = oh->http->GetModeData(oh->http, &config); 431da4961c7SRebecca Cran if (EFI_ERROR(status)) 432da4961c7SRebecca Cran return (efi_status_to_errno(status)); 433da4961c7SRebecca Cran status = oh->http->Configure(oh->http, NULL); 434da4961c7SRebecca Cran if (EFI_ERROR(status)) 435da4961c7SRebecca Cran return (efi_status_to_errno(status)); 436da4961c7SRebecca Cran status = oh->http->Configure(oh->http, &config); 437da4961c7SRebecca Cran if (EFI_ERROR(status)) 438da4961c7SRebecca Cran return (efi_status_to_errno(status)); 439da4961c7SRebecca Cran 440da4961c7SRebecca Cran /* Send the read request */ 441da4961c7SRebecca Cran done = false; 442da4961c7SRebecca Cran status = BS->CreateEvent(EVT_NOTIFY_SIGNAL, TPL_CALLBACK, notify, 443da4961c7SRebecca Cran &done, &token.Event); 444da4961c7SRebecca Cran if (EFI_ERROR(status)) 445da4961c7SRebecca Cran return (efi_status_to_errno(status)); 446da4961c7SRebecca Cran 447da4961c7SRebecca Cran /* extract the host portion of the URL */ 448da4961c7SRebecca Cran host = strdup(oh->uri_base); 449da4961c7SRebecca Cran if (host == NULL) 450da4961c7SRebecca Cran return (ENOMEM); 451da4961c7SRebecca Cran hostp = host; 452da4961c7SRebecca Cran /* Remove the protocol scheme */ 453da4961c7SRebecca Cran c = strchr(host, '/'); 454da4961c7SRebecca Cran if (c != NULL && *(c + 1) == '/') 455da4961c7SRebecca Cran hostp = (c + 2); 456da4961c7SRebecca Cran 457da4961c7SRebecca Cran /* Remove any path information */ 458da4961c7SRebecca Cran c = strchr(hostp, '/'); 459da4961c7SRebecca Cran if (c != NULL) 460da4961c7SRebecca Cran *c = '\0'; 461da4961c7SRebecca Cran 462da4961c7SRebecca Cran token.Status = EFI_NOT_READY; 463da4961c7SRebecca Cran token.Message = &message; 464da4961c7SRebecca Cran message.Data.Request = &request; 465da4961c7SRebecca Cran message.HeaderCount = 3; 466da4961c7SRebecca Cran message.Headers = headers; 467da4961c7SRebecca Cran message.BodyLength = 0; 468da4961c7SRebecca Cran message.Body = NULL; 469da4961c7SRebecca Cran request.Method = HttpMethodGet; 470da4961c7SRebecca Cran request.Url = calloc(strlen(oh->uri_base) + strlen(path) + 1, 2); 471*5bca29b8SToomas Soome headers[0].FieldName = (CHAR8 *)"Host"; 472*5bca29b8SToomas Soome headers[0].FieldValue = (CHAR8 *)hostp; 473*5bca29b8SToomas Soome headers[1].FieldName = (CHAR8 *)"Connection"; 474*5bca29b8SToomas Soome headers[1].FieldValue = (CHAR8 *)"close"; 475*5bca29b8SToomas Soome headers[2].FieldName = (CHAR8 *)"Accept"; 476*5bca29b8SToomas Soome headers[2].FieldValue = (CHAR8 *)"*/*"; 477da4961c7SRebecca Cran cpy8to16(oh->uri_base, request.Url, strlen(oh->uri_base)); 478da4961c7SRebecca Cran cpy8to16(path, request.Url + strlen(oh->uri_base), strlen(path)); 479da4961c7SRebecca Cran status = oh->http->Request(oh->http, &token); 480da4961c7SRebecca Cran free(request.Url); 481da4961c7SRebecca Cran free(host); 482da4961c7SRebecca Cran if (EFI_ERROR(status)) { 483da4961c7SRebecca Cran BS->CloseEvent(token.Event); 484da4961c7SRebecca Cran return (efi_status_to_errno(status)); 485da4961c7SRebecca Cran } 486da4961c7SRebecca Cran 487da4961c7SRebecca Cran polltime = 0; 488da4961c7SRebecca Cran while (!done && polltime < EFIHTTP_POLL_TIMEOUT) { 489da4961c7SRebecca Cran status = oh->http->Poll(oh->http); 490da4961c7SRebecca Cran if (EFI_ERROR(status)) 491da4961c7SRebecca Cran break; 492da4961c7SRebecca Cran 493da4961c7SRebecca Cran if (!done) { 494da4961c7SRebecca Cran delay(100 * 1000); 495da4961c7SRebecca Cran polltime += 100; 496da4961c7SRebecca Cran } 497da4961c7SRebecca Cran } 498da4961c7SRebecca Cran BS->CloseEvent(token.Event); 499da4961c7SRebecca Cran if (EFI_ERROR(token.Status)) 500da4961c7SRebecca Cran return (efi_status_to_errno(token.Status)); 501da4961c7SRebecca Cran 502da4961c7SRebecca Cran /* Wait for the read response */ 503da4961c7SRebecca Cran done = false; 504da4961c7SRebecca Cran status = BS->CreateEvent(EVT_NOTIFY_SIGNAL, TPL_CALLBACK, notify, 505da4961c7SRebecca Cran &done, &token.Event); 506da4961c7SRebecca Cran if (EFI_ERROR(status)) 507da4961c7SRebecca Cran return (efi_status_to_errno(status)); 508da4961c7SRebecca Cran token.Status = EFI_NOT_READY; 509da4961c7SRebecca Cran token.Message = &message; 510da4961c7SRebecca Cran message.Data.Response = &response; 511da4961c7SRebecca Cran message.HeaderCount = 0; 512da4961c7SRebecca Cran message.Headers = NULL; 513da4961c7SRebecca Cran message.BodyLength = 0; 514da4961c7SRebecca Cran message.Body = NULL; 515da4961c7SRebecca Cran response.StatusCode = HTTP_STATUS_UNSUPPORTED_STATUS; 516da4961c7SRebecca Cran status = oh->http->Response(oh->http, &token); 517da4961c7SRebecca Cran if (EFI_ERROR(status)) { 518da4961c7SRebecca Cran BS->CloseEvent(token.Event); 519da4961c7SRebecca Cran return (efi_status_to_errno(status)); 520da4961c7SRebecca Cran } 521da4961c7SRebecca Cran 522da4961c7SRebecca Cran polltime = 0; 523da4961c7SRebecca Cran while (!done && polltime < EFIHTTP_POLL_TIMEOUT) { 524da4961c7SRebecca Cran status = oh->http->Poll(oh->http); 525da4961c7SRebecca Cran if (EFI_ERROR(status)) 526da4961c7SRebecca Cran break; 527da4961c7SRebecca Cran 528da4961c7SRebecca Cran if (!done) { 529da4961c7SRebecca Cran delay(100 * 1000); 530da4961c7SRebecca Cran polltime += 100; 531da4961c7SRebecca Cran } 532da4961c7SRebecca Cran } 533da4961c7SRebecca Cran BS->CloseEvent(token.Event); 534da4961c7SRebecca Cran if (EFI_ERROR(token.Status)) { 535da4961c7SRebecca Cran BS->FreePool(message.Headers); 536da4961c7SRebecca Cran return (efi_status_to_errno(token.Status)); 537da4961c7SRebecca Cran } 538da4961c7SRebecca Cran if (response.StatusCode != HTTP_STATUS_200_OK) { 539da4961c7SRebecca Cran BS->FreePool(message.Headers); 540da4961c7SRebecca Cran return (EIO); 541da4961c7SRebecca Cran } 542da4961c7SRebecca Cran fh->size = 0; 543da4961c7SRebecca Cran fh->is_dir = false; 544da4961c7SRebecca Cran for (i = 0; i < message.HeaderCount; i++) { 545*5bca29b8SToomas Soome if (strcasecmp((const char *)message.Headers[i].FieldName, 546da4961c7SRebecca Cran "Content-Length") == 0) 547*5bca29b8SToomas Soome fh->size = strtoul((const char *) 548*5bca29b8SToomas Soome message.Headers[i].FieldValue, NULL, 10); 549*5bca29b8SToomas Soome else if (strcasecmp((const char *)message.Headers[i].FieldName, 550da4961c7SRebecca Cran "Content-type") == 0) { 551*5bca29b8SToomas Soome if (strncmp((const char *)message.Headers[i].FieldValue, 552*5bca29b8SToomas Soome "text/html", 9) == 0) 553da4961c7SRebecca Cran fh->is_dir = true; 554da4961c7SRebecca Cran } 555da4961c7SRebecca Cran } 556da4961c7SRebecca Cran 557da4961c7SRebecca Cran return (0); 558da4961c7SRebecca Cran } 559da4961c7SRebecca Cran 560da4961c7SRebecca Cran static int 561da4961c7SRebecca Cran efihttp_fs_open(const char *path, struct open_file *f) 562da4961c7SRebecca Cran { 563da4961c7SRebecca Cran char *path_slash; 564da4961c7SRebecca Cran int err; 565da4961c7SRebecca Cran 5661ee03da2SRebecca Cran if (!efihttp_init_done) 5671ee03da2SRebecca Cran return (ENXIO); 568da4961c7SRebecca Cran /* 569da4961c7SRebecca Cran * If any path fails to open, try with a trailing slash in 570da4961c7SRebecca Cran * case it's a directory. 571da4961c7SRebecca Cran */ 572da4961c7SRebecca Cran err = _efihttp_fs_open(path, f); 573da4961c7SRebecca Cran if (err != 0) { 574da4961c7SRebecca Cran path_slash = malloc(strlen(path) + 2); 575da4961c7SRebecca Cran if (path_slash == NULL) 576da4961c7SRebecca Cran return (ENOMEM); 577da4961c7SRebecca Cran strcpy(path_slash, path); 578da4961c7SRebecca Cran strcat(path_slash, "/"); 579da4961c7SRebecca Cran err = _efihttp_fs_open(path_slash, f); 580da4961c7SRebecca Cran free(path_slash); 581da4961c7SRebecca Cran } 582da4961c7SRebecca Cran return (err); 583da4961c7SRebecca Cran } 584da4961c7SRebecca Cran 585da4961c7SRebecca Cran static int 586da4961c7SRebecca Cran efihttp_fs_close(struct open_file *f) 587da4961c7SRebecca Cran { 588da4961c7SRebecca Cran return (0); 589da4961c7SRebecca Cran } 590da4961c7SRebecca Cran 591da4961c7SRebecca Cran static int 592da4961c7SRebecca Cran _efihttp_fs_read(struct open_file *f, void *buf, size_t size, size_t *resid) 593da4961c7SRebecca Cran { 594da4961c7SRebecca Cran EFI_HTTP_TOKEN token; 595da4961c7SRebecca Cran EFI_HTTP_MESSAGE message; 596da4961c7SRebecca Cran EFI_STATUS status; 597da4961c7SRebecca Cran struct devdesc *dev; 598da4961c7SRebecca Cran struct open_efihttp *oh; 599da4961c7SRebecca Cran struct file_efihttp *fh; 600da4961c7SRebecca Cran bool done; 601da4961c7SRebecca Cran int polltime; 602da4961c7SRebecca Cran 603da4961c7SRebecca Cran fh = (struct file_efihttp *)f->f_fsdata; 604da4961c7SRebecca Cran 605da4961c7SRebecca Cran if (fh->size > 0 && fh->offset >= fh->size) { 606da4961c7SRebecca Cran if (resid != NULL) 607da4961c7SRebecca Cran *resid = size; 608da4961c7SRebecca Cran 609da4961c7SRebecca Cran return 0; 610da4961c7SRebecca Cran } 611da4961c7SRebecca Cran 612da4961c7SRebecca Cran dev = (struct devdesc *)f->f_devdata; 613da4961c7SRebecca Cran oh = (struct open_efihttp *)dev->d_opendata; 614da4961c7SRebecca Cran done = false; 615da4961c7SRebecca Cran status = BS->CreateEvent(EVT_NOTIFY_SIGNAL, TPL_CALLBACK, notify, 616da4961c7SRebecca Cran &done, &token.Event); 617da4961c7SRebecca Cran if (EFI_ERROR(status)) { 618da4961c7SRebecca Cran return (efi_status_to_errno(status)); 619da4961c7SRebecca Cran } 620da4961c7SRebecca Cran token.Status = EFI_NOT_READY; 621da4961c7SRebecca Cran token.Message = &message; 622da4961c7SRebecca Cran message.Data.Request = NULL; 623da4961c7SRebecca Cran message.HeaderCount = 0; 624da4961c7SRebecca Cran message.Headers = NULL; 625da4961c7SRebecca Cran message.BodyLength = size; 626da4961c7SRebecca Cran message.Body = buf; 627da4961c7SRebecca Cran status = oh->http->Response(oh->http, &token); 628da4961c7SRebecca Cran if (status == EFI_CONNECTION_FIN) { 629da4961c7SRebecca Cran if (resid) 630da4961c7SRebecca Cran *resid = size; 631da4961c7SRebecca Cran return (0); 632da4961c7SRebecca Cran } else if (EFI_ERROR(status)) { 633da4961c7SRebecca Cran BS->CloseEvent(token.Event); 634da4961c7SRebecca Cran return (efi_status_to_errno(status)); 635da4961c7SRebecca Cran } 636da4961c7SRebecca Cran polltime = 0; 637da4961c7SRebecca Cran while (!done && polltime < EFIHTTP_POLL_TIMEOUT) { 638da4961c7SRebecca Cran status = oh->http->Poll(oh->http); 639da4961c7SRebecca Cran if (EFI_ERROR(status)) 640da4961c7SRebecca Cran break; 641da4961c7SRebecca Cran 642da4961c7SRebecca Cran if (!done) { 643da4961c7SRebecca Cran delay(100 * 1000); 644da4961c7SRebecca Cran polltime += 100; 645da4961c7SRebecca Cran } 646da4961c7SRebecca Cran } 647da4961c7SRebecca Cran BS->CloseEvent(token.Event); 648da4961c7SRebecca Cran if (token.Status == EFI_CONNECTION_FIN) { 649da4961c7SRebecca Cran if (resid) 650da4961c7SRebecca Cran *resid = size; 651da4961c7SRebecca Cran return (0); 652da4961c7SRebecca Cran } else if (EFI_ERROR(token.Status)) 653da4961c7SRebecca Cran return (efi_status_to_errno(token.Status)); 654da4961c7SRebecca Cran if (resid) 655da4961c7SRebecca Cran *resid = size - message.BodyLength; 656da4961c7SRebecca Cran fh->offset += message.BodyLength; 657da4961c7SRebecca Cran return (0); 658da4961c7SRebecca Cran } 659da4961c7SRebecca Cran 660da4961c7SRebecca Cran static int 661da4961c7SRebecca Cran efihttp_fs_read(struct open_file *f, void *buf, size_t size, size_t *resid) 662da4961c7SRebecca Cran { 663da4961c7SRebecca Cran size_t res; 664da4961c7SRebecca Cran int err; 665da4961c7SRebecca Cran 666da4961c7SRebecca Cran while (size > 0) { 667da4961c7SRebecca Cran err = _efihttp_fs_read(f, buf, size, &res); 668da4961c7SRebecca Cran if (err != 0 || res == size) 669da4961c7SRebecca Cran goto end; 670da4961c7SRebecca Cran buf += (size - res); 671da4961c7SRebecca Cran size = res; 672da4961c7SRebecca Cran } 673da4961c7SRebecca Cran end: 674da4961c7SRebecca Cran if (resid) 675da4961c7SRebecca Cran *resid = size; 676da4961c7SRebecca Cran return (err); 677da4961c7SRebecca Cran } 678da4961c7SRebecca Cran 679da4961c7SRebecca Cran static int 680da4961c7SRebecca Cran efihttp_fs_write(struct open_file *f, const void *buf, size_t size, size_t *resid) 681da4961c7SRebecca Cran { 682da4961c7SRebecca Cran return (EIO); 683da4961c7SRebecca Cran } 684da4961c7SRebecca Cran 685da4961c7SRebecca Cran static off_t 686da4961c7SRebecca Cran efihttp_fs_seek(struct open_file *f, off_t offset, int where) 687da4961c7SRebecca Cran { 688da4961c7SRebecca Cran struct file_efihttp *fh; 689da4961c7SRebecca Cran char *path; 690da4961c7SRebecca Cran void *buf; 691da4961c7SRebecca Cran size_t res, res2; 692da4961c7SRebecca Cran int err; 693da4961c7SRebecca Cran 694da4961c7SRebecca Cran fh = (struct file_efihttp *)f->f_fsdata; 695da4961c7SRebecca Cran if (where == SEEK_SET && fh->offset == offset) 696da4961c7SRebecca Cran return (0); 697da4961c7SRebecca Cran if (where == SEEK_SET && fh->offset < offset) { 698da4961c7SRebecca Cran buf = malloc(1500); 699da4961c7SRebecca Cran res = offset - fh->offset; 700da4961c7SRebecca Cran while (res > 0) { 701da4961c7SRebecca Cran err = _efihttp_fs_read(f, buf, min(1500, res), &res2); 702da4961c7SRebecca Cran if (err != 0) { 703da4961c7SRebecca Cran free(buf); 704da4961c7SRebecca Cran return (err); 705da4961c7SRebecca Cran } 706da4961c7SRebecca Cran res -= min(1500, res) - res2; 707da4961c7SRebecca Cran } 708da4961c7SRebecca Cran free(buf); 709da4961c7SRebecca Cran return (0); 710da4961c7SRebecca Cran } else if (where == SEEK_SET) { 711da4961c7SRebecca Cran path = fh->path; 712da4961c7SRebecca Cran fh->path = NULL; 713da4961c7SRebecca Cran efihttp_fs_close(f); 714da4961c7SRebecca Cran err = efihttp_fs_open(path, f); 715da4961c7SRebecca Cran free(path); 716da4961c7SRebecca Cran if (err != 0) 717da4961c7SRebecca Cran return (err); 718da4961c7SRebecca Cran return efihttp_fs_seek(f, offset, where); 719da4961c7SRebecca Cran } 720da4961c7SRebecca Cran return (EIO); 721da4961c7SRebecca Cran } 722da4961c7SRebecca Cran 723da4961c7SRebecca Cran static int 724da4961c7SRebecca Cran efihttp_fs_stat(struct open_file *f, struct stat *sb) 725da4961c7SRebecca Cran { 726da4961c7SRebecca Cran struct file_efihttp *fh; 727da4961c7SRebecca Cran 728da4961c7SRebecca Cran fh = (struct file_efihttp *)f->f_fsdata; 729da4961c7SRebecca Cran memset(sb, 0, sizeof(*sb)); 730da4961c7SRebecca Cran sb->st_nlink = 1; 731da4961c7SRebecca Cran sb->st_mode = 0777 | (fh->is_dir ? S_IFDIR : S_IFREG); 732da4961c7SRebecca Cran sb->st_size = fh->size; 733da4961c7SRebecca Cran return (0); 734da4961c7SRebecca Cran } 735da4961c7SRebecca Cran 736da4961c7SRebecca Cran static int 737da4961c7SRebecca Cran efihttp_fs_readdir(struct open_file *f, struct dirent *d) 738da4961c7SRebecca Cran { 739da4961c7SRebecca Cran static char *dirbuf = NULL, *db2, *cursor; 740da4961c7SRebecca Cran static int dirbuf_len = 0; 741da4961c7SRebecca Cran char *end; 742da4961c7SRebecca Cran struct file_efihttp *fh; 743da4961c7SRebecca Cran 744da4961c7SRebecca Cran fh = (struct file_efihttp *)f->f_fsdata; 745da4961c7SRebecca Cran if (dirbuf_len < fh->size) { 746da4961c7SRebecca Cran db2 = realloc(dirbuf, fh->size); 747da4961c7SRebecca Cran if (db2 == NULL) { 748da4961c7SRebecca Cran free(dirbuf); 749da4961c7SRebecca Cran return (ENOMEM); 750da4961c7SRebecca Cran } else 751da4961c7SRebecca Cran dirbuf = db2; 752da4961c7SRebecca Cran 753da4961c7SRebecca Cran dirbuf_len = fh->size; 754da4961c7SRebecca Cran } 755da4961c7SRebecca Cran 756da4961c7SRebecca Cran if (fh->offset != fh->size) { 757da4961c7SRebecca Cran efihttp_fs_seek(f, 0, SEEK_SET); 758da4961c7SRebecca Cran efihttp_fs_read(f, dirbuf, dirbuf_len, NULL); 759da4961c7SRebecca Cran cursor = dirbuf; 760da4961c7SRebecca Cran } 761da4961c7SRebecca Cran 762da4961c7SRebecca Cran cursor = strstr(cursor, "<a href=\""); 763da4961c7SRebecca Cran if (cursor == NULL) 764da4961c7SRebecca Cran return (ENOENT); 765da4961c7SRebecca Cran cursor += 9; 766da4961c7SRebecca Cran end = strchr(cursor, '"'); 767da4961c7SRebecca Cran if (*(end - 1) == '/') { 768da4961c7SRebecca Cran end--; 769da4961c7SRebecca Cran d->d_type = DT_DIR; 770da4961c7SRebecca Cran } else 771da4961c7SRebecca Cran d->d_type = DT_REG; 772da4961c7SRebecca Cran memcpy(d->d_name, cursor, end - cursor); 773da4961c7SRebecca Cran d->d_name[end - cursor] = '\0'; 774da4961c7SRebecca Cran 775da4961c7SRebecca Cran return (0); 776da4961c7SRebecca Cran } 777