Add http and ip4_config2 only if they are not already provided in the handle. The current use of pxe is only to store an ip address if a dhcp ack is received, this address is used by grub. Add pxe only if a dhcp ack is actually received.
Signed-off-by: Adriano Cordova <[email protected]> --- include/efi_loader.h | 8 +- lib/efi_loader/efi_http.c | 30 ++++- lib/efi_loader/efi_ipconfig.c | 36 +++++- lib/efi_loader/efi_net.c | 203 +++++++++++++++++++++++----------- 4 files changed, 199 insertions(+), 78 deletions(-) diff --git a/include/efi_loader.h b/include/efi_loader.h index 35f500fd97d..ad234dbe6b3 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -677,10 +677,14 @@ efi_status_t efi_net_init(void); efi_status_t efi_net_do_start(void); /* Called by efi_net_register to make the ip4 config2 protocol available */ efi_status_t efi_ipconfig_register(const efi_handle_t handle, - struct efi_ip4_config2_protocol *ip4config); + struct efi_ip4_config2_protocol **ip4config); +efi_status_t efi_ipconfig_unregister(const efi_handle_t handle, + struct efi_ip4_config2_protocol *ip4config); /* Called by efi_net_register to make the http protocol available */ efi_status_t efi_http_register(const efi_handle_t handle, - struct efi_service_binding_protocol *http_service_binding); + struct efi_service_binding_protocol **http_service_binding); +efi_status_t efi_http_unregister(const efi_handle_t handle, + struct efi_service_binding_protocol *http_service_binding); /* Called by bootefi to make the watchdog available */ efi_status_t efi_watchdog_register(void); efi_status_t efi_initrd_register(void); diff --git a/lib/efi_loader/efi_http.c b/lib/efi_loader/efi_http.c index 189317fe2d2..dcef875f5b5 100644 --- a/lib/efi_loader/efi_http.c +++ b/lib/efi_loader/efi_http.c @@ -486,23 +486,45 @@ static efi_status_t EFIAPI efi_http_service_binding_destroy_child( * */ efi_status_t efi_http_register(const efi_handle_t handle, - struct efi_service_binding_protocol *http_service_binding) + struct efi_service_binding_protocol **http_service_binding) { efi_status_t r = EFI_SUCCESS; + r = efi_allocate_pool(EFI_LOADER_DATA, sizeof(**http_service_binding), + (void **)http_service_binding); + if (r != EFI_SUCCESS) + return r; r = efi_add_protocol(handle, &efi_http_service_binding_guid, - http_service_binding); + *http_service_binding); if (r != EFI_SUCCESS) goto failure_to_add_protocol; - http_service_binding->create_child = efi_http_service_binding_create_child; - http_service_binding->destroy_child = efi_http_service_binding_destroy_child; + (*http_service_binding)->create_child = efi_http_service_binding_create_child; + (*http_service_binding)->destroy_child = efi_http_service_binding_destroy_child; return EFI_SUCCESS; failure_to_add_protocol: return r; } +/** + * efi_http_unregister() - unregister the http protocol + * + */ +efi_status_t efi_http_unregister(const efi_handle_t handle, + struct efi_service_binding_protocol *http_service_binding) +{ + efi_status_t r = EFI_SUCCESS; + + r = efi_uninstall_protocol(handle, &efi_http_service_binding_guid, + http_service_binding, true); + if (r != EFI_SUCCESS) + return r; + efi_free_pool(http_service_binding); + + return EFI_SUCCESS; +} + enum efi_http_status_code efi_u32_to_httpstatus(u32 status) { switch (status) { diff --git a/lib/efi_loader/efi_ipconfig.c b/lib/efi_loader/efi_ipconfig.c index 9f51f77fa9a..18f659f4ed1 100644 --- a/lib/efi_loader/efi_ipconfig.c +++ b/lib/efi_loader/efi_ipconfig.c @@ -194,12 +194,18 @@ static efi_status_t EFIAPI efi_ip4_config2_unregister_notify(struct efi_ip4_conf * */ efi_status_t efi_ipconfig_register(const efi_handle_t handle, - struct efi_ip4_config2_protocol *ip4config) + struct efi_ip4_config2_protocol **ip4config) { efi_status_t r = EFI_SUCCESS; + if (!ip4config) + return EFI_INVALID_PARAMETER; + + r = efi_allocate_pool(EFI_LOADER_DATA, sizeof(**ip4config), (void **)ip4config); + if (r != EFI_SUCCESS) + return r; r = efi_add_protocol(handle, &efi_ip4_config2_guid, - ip4config); + *ip4config); if (r != EFI_SUCCESS) { log_err("ERROR: Failure to add protocol\n"); return r; @@ -207,10 +213,28 @@ efi_status_t efi_ipconfig_register(const efi_handle_t handle, memcpy(current_mac_addr, eth_get_ethaddr(), 6); - ip4config->set_data = efi_ip4_config2_set_data; - ip4config->get_data = efi_ip4_config2_get_data; - ip4config->register_data_notify = efi_ip4_config2_register_notify; - ip4config->unregister_data_notify = efi_ip4_config2_unregister_notify; + (*ip4config)->set_data = efi_ip4_config2_set_data; + (*ip4config)->get_data = efi_ip4_config2_get_data; + (*ip4config)->register_data_notify = efi_ip4_config2_register_notify; + (*ip4config)->unregister_data_notify = efi_ip4_config2_unregister_notify; + + return EFI_SUCCESS; +} + +/** + * efi_ipconfig_unregister() - unregister the ip4_config2 protocol + * + */ +efi_status_t efi_ipconfig_unregister(const efi_handle_t handle, + struct efi_ip4_config2_protocol *ip4config) +{ + efi_status_t r = EFI_SUCCESS; + + r = efi_uninstall_protocol(handle, &efi_ip4_config2_guid, + ip4config, true); + if (r != EFI_SUCCESS) + return r; + efi_free_pool(ip4config); return EFI_SUCCESS; } diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c index fd43eec4c03..5a00e7a570c 100644 --- a/lib/efi_loader/efi_net.c +++ b/lib/efi_loader/efi_net.c @@ -19,6 +19,7 @@ #include <efi_loader.h> #include <dm.h> +#include <dm/lists.h> #include <linux/sizes.h> #include <malloc.h> #include <vsprintf.h> @@ -31,6 +32,8 @@ const efi_guid_t efi_net_guid = EFI_SIMPLE_NETWORK_PROTOCOL_GUID; static const efi_guid_t efi_pxe_base_code_protocol_guid = EFI_PXE_BASE_CODE_PROTOCOL_GUID; +static const efi_guid_t efi_ip4_config2_guid = EFI_IP4_CONFIG2_PROTOCOL_GUID; +static const efi_guid_t efi_http_service_binding_guid = EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID; struct dp_entry { struct efi_device_path *net_dp; @@ -93,10 +96,10 @@ struct efi_net_obj { struct efi_pxe_base_code_protocol pxe; struct efi_pxe_mode pxe_mode; #if IS_ENABLED(CONFIG_EFI_IP4_CONFIG2_PROTOCOL) - struct efi_ip4_config2_protocol ip4_config2; + struct efi_ip4_config2_protocol *ip4_config2; #endif #if IS_ENABLED(CONFIG_EFI_HTTP_PROTOCOL) - struct efi_service_binding_protocol http_service_binding; + struct efi_service_binding_protocol *http_service_binding; #endif void *new_tx_packet; void *transmit_buffer; @@ -761,6 +764,8 @@ out: return EFI_EXIT(ret); } +efi_status_t efi_net_add_pxe(struct efi_net_obj *netobj); + /** * efi_net_set_dhcp_ack() - take note of a selected DHCP IP address * @@ -795,9 +800,12 @@ void efi_net_set_dhcp_ack(void *pkt, int len) next_dhcp_entry++; next_dhcp_entry %= MAX_NUM_DHCP_ENTRIES; - for (i = 0; i < MAX_EFI_NET_OBJS; i++) { - if (net_objs[i] && net_objs[i]->dev == dev) { - net_objs[i]->pxe_mode.dhcp_ack = **dhcp_ack; + if (efi_obj_list_initialized == EFI_SUCCESS) { + for (i = 0; i < MAX_EFI_NET_OBJS; i++) { + if (net_objs[i] && net_objs[i]->dev == dev) { + efi_net_add_pxe(net_objs[i]); + break; + } } } } @@ -1069,6 +1077,52 @@ static struct efi_device_path *efi_netobj_get_dp(struct efi_net_obj *netobj) return NULL; } +/** + * efi_net_add_pxe() - install the pxe protocol to a netobj + * + * @netobj: pointer to efi_net_obj + * Return: status code + */ +efi_status_t efi_net_add_pxe(struct efi_net_obj *netobj) +{ + efi_status_t r = EFI_SUCCESS; + struct efi_handler *phandler; + int i, j; + + r = efi_search_protocol(netobj->handle, &efi_pxe_base_code_protocol_guid, &phandler); + if (r == EFI_SUCCESS) + return r; + + i = (next_dhcp_entry + MAX_NUM_DHCP_ENTRIES - 1) % MAX_NUM_DHCP_ENTRIES; + for (j = 0; netobj->dev && dhcp_cache[i].is_valid && j < MAX_NUM_DHCP_ENTRIES; + i = (i + MAX_NUM_DHCP_ENTRIES - 1) % MAX_NUM_DHCP_ENTRIES, j++) { + if (netobj->dev == dhcp_cache[i].dev) { + netobj->pxe_mode.dhcp_ack = *dhcp_cache[i].dhcp_ack; + r = efi_add_protocol(netobj->handle, &efi_pxe_base_code_protocol_guid, + &netobj->pxe); + if (r != EFI_SUCCESS) + return r; + netobj->pxe.revision = EFI_PXE_BASE_CODE_PROTOCOL_REVISION; + netobj->pxe.start = efi_pxe_base_code_start; + netobj->pxe.stop = efi_pxe_base_code_stop; + netobj->pxe.dhcp = efi_pxe_base_code_dhcp; + netobj->pxe.discover = efi_pxe_base_code_discover; + netobj->pxe.mtftp = efi_pxe_base_code_mtftp; + netobj->pxe.udp_write = efi_pxe_base_code_udp_write; + netobj->pxe.udp_read = efi_pxe_base_code_udp_read; + netobj->pxe.set_ip_filter = efi_pxe_base_code_set_ip_filter; + netobj->pxe.arp = efi_pxe_base_code_arp; + netobj->pxe.set_parameters = efi_pxe_base_code_set_parameters; + netobj->pxe.set_station_ip = efi_pxe_base_code_set_station_ip; + netobj->pxe.set_packets = efi_pxe_base_code_set_packets; + netobj->pxe.mode = &netobj->pxe_mode; + break; + } + } + + return EFI_SUCCESS; +} + /** * efi_netobj_start() - start an efi net device * @@ -1102,15 +1156,8 @@ efi_status_t efi_netobj_start(struct efi_net_obj *netobj) if (r != EFI_SUCCESS) return r; set_addr: -#ifdef CONFIG_EFI_HTTP_PROTOCOL - /* - * No harm on doing the following. If the PXE handle is present, the client could - * find it and try to get its IP address from it. In here the PXE handle is present - * but the PXE protocol is not yet implmenented, so we add this in the meantime. - */ efi_net_get_addr((struct efi_ipv4_address *)&netobj->pxe_mode.station_ip, (struct efi_ipv4_address *)&netobj->pxe_mode.subnet_mask, NULL, netobj->dev); -#endif return 0; } @@ -1147,16 +1194,20 @@ static int efi_netobj_init(struct efi_net_obj *netobj) { efi_status_t r; struct udevice *dev; + struct efi_handler *phandler; void *transmit_buffer = NULL; uchar **receive_buffer = NULL; size_t *receive_lengths = NULL; - int i, j; + int i; - if (!netobj || !netobj->net || efi_netobj_is_active(netobj)) + if (!netobj || !netobj->net) return 0; dev = netobj->dev; + if (efi_netobj_is_active(netobj)) + goto set_timers; + if (!netobj->net_mode) netobj->net_mode = calloc(1, sizeof(*netobj->net_mode)); if (!netobj->net_mode) @@ -1203,11 +1254,6 @@ static int efi_netobj_init(struct efi_net_obj *netobj) netobj->net); if (r != EFI_SUCCESS) goto failure_to_add_protocol; - - r = efi_add_protocol(netobj->handle, &efi_pxe_base_code_protocol_guid, - &netobj->pxe); - if (r != EFI_SUCCESS) - goto failure_to_add_protocol; netobj->net->revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION; netobj->net->start = efi_net_start; netobj->net->stop = efi_net_stop; @@ -1233,38 +1279,15 @@ static int efi_netobj_init(struct efi_net_obj *netobj) netobj->net_mode->max_packet_size = PKTSIZE; netobj->net_mode->if_type = ARP_ETHER; - netobj->pxe.revision = EFI_PXE_BASE_CODE_PROTOCOL_REVISION; - netobj->pxe.start = efi_pxe_base_code_start; - netobj->pxe.stop = efi_pxe_base_code_stop; - netobj->pxe.dhcp = efi_pxe_base_code_dhcp; - netobj->pxe.discover = efi_pxe_base_code_discover; - netobj->pxe.mtftp = efi_pxe_base_code_mtftp; - netobj->pxe.udp_write = efi_pxe_base_code_udp_write; - netobj->pxe.udp_read = efi_pxe_base_code_udp_read; - netobj->pxe.set_ip_filter = efi_pxe_base_code_set_ip_filter; - netobj->pxe.arp = efi_pxe_base_code_arp; - netobj->pxe.set_parameters = efi_pxe_base_code_set_parameters; - netobj->pxe.set_station_ip = efi_pxe_base_code_set_station_ip; - netobj->pxe.set_packets = efi_pxe_base_code_set_packets; - netobj->pxe.mode = &netobj->pxe_mode; + r = efi_net_add_pxe(netobj); + if (r != EFI_SUCCESS) + return -1; r = EFI_CALL(efi_connect_controller(netobj->handle, NULL, NULL, 0)); if (r != EFI_SUCCESS) return -1; - /* - * Scan dhcp entries for one corresponding - * to this udevice, from newest to oldest - */ - i = (next_dhcp_entry + MAX_NUM_DHCP_ENTRIES - 1) % MAX_NUM_DHCP_ENTRIES; - for (j = 0; dev && dhcp_cache[i].is_valid && j < MAX_NUM_DHCP_ENTRIES; - i = (i + MAX_NUM_DHCP_ENTRIES - 1) % MAX_NUM_DHCP_ENTRIES, j++) { - if (dev == dhcp_cache[i].dev) { - netobj->pxe_mode.dhcp_ack = *dhcp_cache[i].dhcp_ack; - break; - } - } - +set_timers: /* * Create WaitForPacket event. */ @@ -1299,16 +1322,26 @@ static int efi_netobj_init(struct efi_net_obj *netobj) } #if IS_ENABLED(CONFIG_EFI_IP4_CONFIG2_PROTOCOL) + netobj->ip4_config2 = NULL; + r = efi_search_protocol(netobj->handle, &efi_ip4_config2_guid, &phandler); + if (r == EFI_SUCCESS) + goto http; r = efi_ipconfig_register(netobj->handle, &netobj->ip4_config2); if (r != EFI_SUCCESS) goto failure_to_add_protocol; #endif +http: #ifdef CONFIG_EFI_HTTP_PROTOCOL + netobj->http_service_binding = NULL; + r = efi_search_protocol(netobj->handle, &efi_http_service_binding_guid, &phandler); + if (r == EFI_SUCCESS) + goto out; r = efi_http_register(netobj->handle, &netobj->http_service_binding); if (r != EFI_SUCCESS) goto failure_to_add_protocol; #endif +out: return 0; failure_to_add_protocol: printf("ERROR: Failure to add protocol\n"); @@ -1428,6 +1461,10 @@ struct efi_net_obj *efi_netobj_alloc(efi_handle_t handle, int efi_net_register(void *ctx, struct event *event) { struct udevice *dev; + struct driver *drv; + struct efi_netdev_plat *plat; + efi_handle_t handle; + struct efi_simple_network *net; enum uclass_id id; struct efi_net_obj *netobj; int i, r; @@ -1449,17 +1486,24 @@ int efi_net_register(void *ctx, struct event *event) } } - netobj = efi_netobj_alloc(NULL, NULL, dev); + handle = NULL; + net = NULL; + drv = lists_driver_lookup_name("efi_netdev"); + if (drv && dev->driver == drv) { + plat = dev_get_plat(dev); + handle = plat->handle; + net = plat->snp; + } + + netobj = efi_netobj_alloc(handle, net, dev); if (!netobj) return -1; if (efi_obj_list_initialized == EFI_SUCCESS) { - if (!efi_netobj_is_active(netobj)) { - r = efi_netobj_init(netobj); - if (r) - return -1; - } + r = efi_netobj_init(netobj); + if (r) + return -1; } return 0; @@ -1476,7 +1520,9 @@ int efi_net_register(void *ctx, struct event *event) int efi_net_unregister(void *ctx, struct event *event) { efi_status_t ret = EFI_SUCCESS; + int r; struct udevice *dev; + struct driver *drv; enum uclass_id id; struct efi_net_obj *netobj; struct efi_handler *phandler; @@ -1501,18 +1547,22 @@ int efi_net_unregister(void *ctx, struct event *event) } } - if (!netobj) + if (!netobj || !efi_netobj_is_active(netobj)) return 0; - if (efi_netobj_is_active(netobj)) { + drv = lists_driver_lookup_name("efi_netdev"); + if (!drv) { + log_err("Cannot find driver 'efi_netdev'\n"); + return -1; + } + + if (drv != dev->driver) { ret = EFI_CALL(efi_disconnect_controller(netobj->handle, NULL, NULL)); if (ret != EFI_SUCCESS) return -1; - ret = EFI_CALL(efi_close_event(netobj->wait_for_packet)); if (ret != EFI_SUCCESS) return -1; - ret = EFI_CALL(efi_close_event(netobj->network_timer_event)); if (ret != EFI_SUCCESS) return -1; @@ -1524,22 +1574,43 @@ int efi_net_unregister(void *ctx, struct event *event) if (phandler && phandler->protocol_interface) interface = phandler->protocol_interface; + if (netobj->handle->dev) { + r = efi_unlink_dev(netobj->handle); + if (r) + return -1; + } + } + +#if IS_ENABLED(CONFIG_EFI_IP4_CONFIG2_PROTOCOL) + if (netobj->ip4_config2) { + r = efi_ipconfig_unregister(netobj->handle, netobj->ip4_config2); + if (r != EFI_SUCCESS) + return -1; + netobj->ip4_config2 = NULL; + } +#endif + +#ifdef CONFIG_EFI_HTTP_PROTOCOL + if (netobj->http_service_binding) { + r = efi_http_unregister(netobj->handle, netobj->http_service_binding); + if (r != EFI_SUCCESS) + return -1; + netobj->http_service_binding = NULL; + } +#endif + + if (drv != dev->driver) { ret = efi_delete_handle(netobj->handle); if (ret != EFI_SUCCESS) return -1; efi_free_pool(interface); + if (netobj->net) + free(netobj->net); + if (netobj->net_mode) + free(netobj->net_mode); } - if (netobj->net) { - if (netobj->net->mode) - free(netobj->net->mode); - free(netobj->net); - } - - if (netobj->net_mode) - free(netobj->net_mode); - // Mark as free in the list netobj->handle = NULL; netobj->dev = NULL; @@ -1891,7 +1962,7 @@ efi_status_t efi_net_do_request(u8 *url, enum efi_http_method method, void **buf // Set corresponding udevice dev = NULL; for (i = 0; i < MAX_EFI_NET_OBJS; i++) { - if (net_objs[i] && &net_objs[i]->http_service_binding == parent) + if (net_objs[i] && net_objs[i]->http_service_binding == parent) dev = net_objs[i]->dev; } if (!dev) -- 2.48.1

