Add efi_ipconfig_[un]register and efi_http_[un]register to [un]register the ip4_config2 and the http_service_binding protocol. And add the pxe protocol only if a dhcp_ack was received. The latter makes sense as pxe is otherwise not currently implemented.
Signed-off-by: Adriano Cordova <adriano.cord...@canonical.com> --- 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 | 212 ++++++++++++++++++++++------------ 4 files changed, 201 insertions(+), 85 deletions(-) diff --git a/include/efi_loader.h b/include/efi_loader.h index 3bb95cfeb9..063c0a05fd 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -655,10 +655,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); diff --git a/lib/efi_loader/efi_http.c b/lib/efi_loader/efi_http.c index 20450604ec..8831ad922c 100644 --- a/lib/efi_loader/efi_http.c +++ b/lib/efi_loader/efi_http.c @@ -484,23 +484,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_CALL(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 10035e8a7b..ead2e147bd 100644 --- a/lib/efi_loader/efi_ipconfig.c +++ b/lib/efi_loader/efi_ipconfig.c @@ -193,12 +193,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; @@ -206,10 +212,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_CALL(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 b5284ffe34..c172da4e66 100644 --- a/lib/efi_loader/efi_net.c +++ b/lib/efi_loader/efi_net.c @@ -17,6 +17,7 @@ #include <efi_loader.h> #include <dm.h> +#include <dm/lists.h> #include <linux/sizes.h> #include <malloc.h> #include <vsprintf.h> @@ -29,6 +30,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; static struct wget_http_info efi_wget_info = { .set_bootdev = false, @@ -80,10 +83,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; @@ -755,6 +758,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 * @@ -789,9 +794,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; + } } } } @@ -1058,6 +1066,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 r; +} + /** * efi_netobj_start() - start an efi net device * @@ -1069,7 +1123,7 @@ efi_status_t efi_netobj_start(struct efi_net_obj *netobj) { efi_status_t r = EFI_SUCCESS; struct efi_device_path *net_dp; - int i; + if (!efi_netobj_is_active(netobj)) return r; @@ -1091,16 +1145,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 + (struct efi_ipv4_address *)&netobj->pxe_mode.subnet_mask, NULL, netobj->dev); return 0; } @@ -1137,16 +1183,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; uchar **receive_buffer; size_t *receive_lengths; - 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) @@ -1193,11 +1243,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; @@ -1223,38 +1268,13 @@ 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; - - ret = EFI_CALL(efi_connect_controller(net_objs[i]->handle, NULL, NULL, 0)); - if (ret != EFI_SUCCESS) - return -1; + efi_net_add_pxe(netobj); - /* - * 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; - } - } + r = EFI_CALL(efi_connect_controller(netobj->handle, NULL, NULL, 0)); + if (r != EFI_SUCCESS) + return -1; +set_timers: /* * Create WaitForPacket event. */ @@ -1289,16 +1309,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"); @@ -1316,7 +1346,6 @@ out_of_resources: efi_status_t efi_net_init(void) { int i, r; - efi_status_t ret; for (i = 0; i < MAX_EFI_NET_OBJS; i++) { if (net_objs[i]) { @@ -1422,9 +1451,12 @@ 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; - efi_status_t ret; int i, r; dev = event->data.dm.dev; @@ -1444,17 +1476,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; @@ -1471,7 +1510,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; @@ -1496,18 +1537,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; @@ -1517,22 +1562,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; -- 2.43.0