10efe1bcfSAlexander Graf /* 20efe1bcfSAlexander Graf * EFI application network access support 30efe1bcfSAlexander Graf * 40efe1bcfSAlexander Graf * Copyright (c) 2016 Alexander Graf 50efe1bcfSAlexander Graf * 60efe1bcfSAlexander Graf * SPDX-License-Identifier: GPL-2.0+ 70efe1bcfSAlexander Graf */ 80efe1bcfSAlexander Graf 90efe1bcfSAlexander Graf #include <common.h> 100efe1bcfSAlexander Graf #include <efi_loader.h> 110efe1bcfSAlexander Graf #include <inttypes.h> 120efe1bcfSAlexander Graf #include <lcd.h> 130efe1bcfSAlexander Graf #include <malloc.h> 140efe1bcfSAlexander Graf 150efe1bcfSAlexander Graf DECLARE_GLOBAL_DATA_PTR; 160efe1bcfSAlexander Graf 170efe1bcfSAlexander Graf static const efi_guid_t efi_net_guid = EFI_SIMPLE_NETWORK_GUID; 180efe1bcfSAlexander Graf static const efi_guid_t efi_pxe_guid = EFI_PXE_GUID; 190efe1bcfSAlexander Graf static struct efi_pxe_packet *dhcp_ack; 200efe1bcfSAlexander Graf static bool new_rx_packet; 210efe1bcfSAlexander Graf static void *new_tx_packet; 220efe1bcfSAlexander Graf 230efe1bcfSAlexander Graf struct efi_net_obj { 240efe1bcfSAlexander Graf /* Generic EFI object parent class data */ 250efe1bcfSAlexander Graf struct efi_object parent; 260efe1bcfSAlexander Graf /* EFI Interface callback struct for network */ 270efe1bcfSAlexander Graf struct efi_simple_network net; 280efe1bcfSAlexander Graf struct efi_simple_network_mode net_mode; 290efe1bcfSAlexander Graf /* Device path to the network adapter */ 30*d7608abaSOleksandr Tymoshenko struct efi_device_path_mac_addr dp_mac; 31*d7608abaSOleksandr Tymoshenko struct efi_device_path_file_path dp_end; 320efe1bcfSAlexander Graf /* PXE struct to transmit dhcp data */ 330efe1bcfSAlexander Graf struct efi_pxe pxe; 340efe1bcfSAlexander Graf struct efi_pxe_mode pxe_mode; 350efe1bcfSAlexander Graf }; 360efe1bcfSAlexander Graf 370efe1bcfSAlexander Graf static efi_status_t EFIAPI efi_net_start(struct efi_simple_network *this) 380efe1bcfSAlexander Graf { 390efe1bcfSAlexander Graf EFI_ENTRY("%p", this); 400efe1bcfSAlexander Graf 410efe1bcfSAlexander Graf return EFI_EXIT(EFI_SUCCESS); 420efe1bcfSAlexander Graf } 430efe1bcfSAlexander Graf 440efe1bcfSAlexander Graf static efi_status_t EFIAPI efi_net_stop(struct efi_simple_network *this) 450efe1bcfSAlexander Graf { 460efe1bcfSAlexander Graf EFI_ENTRY("%p", this); 470efe1bcfSAlexander Graf 480efe1bcfSAlexander Graf return EFI_EXIT(EFI_SUCCESS); 490efe1bcfSAlexander Graf } 500efe1bcfSAlexander Graf 510efe1bcfSAlexander Graf static efi_status_t EFIAPI efi_net_initialize(struct efi_simple_network *this, 520efe1bcfSAlexander Graf ulong extra_rx, ulong extra_tx) 530efe1bcfSAlexander Graf { 540efe1bcfSAlexander Graf EFI_ENTRY("%p, %lx, %lx", this, extra_rx, extra_tx); 550efe1bcfSAlexander Graf 560efe1bcfSAlexander Graf eth_init(); 570efe1bcfSAlexander Graf 580efe1bcfSAlexander Graf return EFI_EXIT(EFI_SUCCESS); 590efe1bcfSAlexander Graf } 600efe1bcfSAlexander Graf 610efe1bcfSAlexander Graf static efi_status_t EFIAPI efi_net_reset(struct efi_simple_network *this, 620efe1bcfSAlexander Graf int extended_verification) 630efe1bcfSAlexander Graf { 640efe1bcfSAlexander Graf EFI_ENTRY("%p, %x", this, extended_verification); 650efe1bcfSAlexander Graf 660efe1bcfSAlexander Graf return EFI_EXIT(EFI_SUCCESS); 670efe1bcfSAlexander Graf } 680efe1bcfSAlexander Graf 690efe1bcfSAlexander Graf static efi_status_t EFIAPI efi_net_shutdown(struct efi_simple_network *this) 700efe1bcfSAlexander Graf { 710efe1bcfSAlexander Graf EFI_ENTRY("%p", this); 720efe1bcfSAlexander Graf 730efe1bcfSAlexander Graf return EFI_EXIT(EFI_SUCCESS); 740efe1bcfSAlexander Graf } 750efe1bcfSAlexander Graf 760efe1bcfSAlexander Graf static efi_status_t EFIAPI efi_net_receive_filters( 770efe1bcfSAlexander Graf struct efi_simple_network *this, u32 enable, u32 disable, 780efe1bcfSAlexander Graf int reset_mcast_filter, ulong mcast_filter_count, 790efe1bcfSAlexander Graf struct efi_mac_address *mcast_filter) 800efe1bcfSAlexander Graf { 810efe1bcfSAlexander Graf EFI_ENTRY("%p, %x, %x, %x, %lx, %p", this, enable, disable, 820efe1bcfSAlexander Graf reset_mcast_filter, mcast_filter_count, mcast_filter); 830efe1bcfSAlexander Graf 840efe1bcfSAlexander Graf /* XXX Do we care? */ 850efe1bcfSAlexander Graf 860efe1bcfSAlexander Graf return EFI_EXIT(EFI_SUCCESS); 870efe1bcfSAlexander Graf } 880efe1bcfSAlexander Graf 890efe1bcfSAlexander Graf static efi_status_t EFIAPI efi_net_station_address( 900efe1bcfSAlexander Graf struct efi_simple_network *this, int reset, 910efe1bcfSAlexander Graf struct efi_mac_address *new_mac) 920efe1bcfSAlexander Graf { 930efe1bcfSAlexander Graf EFI_ENTRY("%p, %x, %p", this, reset, new_mac); 940efe1bcfSAlexander Graf 950efe1bcfSAlexander Graf return EFI_EXIT(EFI_INVALID_PARAMETER); 960efe1bcfSAlexander Graf } 970efe1bcfSAlexander Graf 980efe1bcfSAlexander Graf static efi_status_t EFIAPI efi_net_statistics(struct efi_simple_network *this, 990efe1bcfSAlexander Graf int reset, ulong *stat_size, 1000efe1bcfSAlexander Graf void *stat_table) 1010efe1bcfSAlexander Graf { 1020efe1bcfSAlexander Graf EFI_ENTRY("%p, %x, %p, %p", this, reset, stat_size, stat_table); 1030efe1bcfSAlexander Graf 1040efe1bcfSAlexander Graf return EFI_EXIT(EFI_INVALID_PARAMETER); 1050efe1bcfSAlexander Graf } 1060efe1bcfSAlexander Graf 1070efe1bcfSAlexander Graf static efi_status_t EFIAPI efi_net_mcastiptomac(struct efi_simple_network *this, 1080efe1bcfSAlexander Graf int ipv6, 1090efe1bcfSAlexander Graf struct efi_ip_address *ip, 1100efe1bcfSAlexander Graf struct efi_mac_address *mac) 1110efe1bcfSAlexander Graf { 1120efe1bcfSAlexander Graf EFI_ENTRY("%p, %x, %p, %p", this, ipv6, ip, mac); 1130efe1bcfSAlexander Graf 1140efe1bcfSAlexander Graf return EFI_EXIT(EFI_INVALID_PARAMETER); 1150efe1bcfSAlexander Graf } 1160efe1bcfSAlexander Graf 1170efe1bcfSAlexander Graf static efi_status_t EFIAPI efi_net_nvdata(struct efi_simple_network *this, 1180efe1bcfSAlexander Graf int read_write, ulong offset, 1190efe1bcfSAlexander Graf ulong buffer_size, char *buffer) 1200efe1bcfSAlexander Graf { 1210efe1bcfSAlexander Graf EFI_ENTRY("%p, %x, %lx, %lx, %p", this, read_write, offset, buffer_size, 1220efe1bcfSAlexander Graf buffer); 1230efe1bcfSAlexander Graf 1240efe1bcfSAlexander Graf return EFI_EXIT(EFI_INVALID_PARAMETER); 1250efe1bcfSAlexander Graf } 1260efe1bcfSAlexander Graf 1270efe1bcfSAlexander Graf static efi_status_t EFIAPI efi_net_get_status(struct efi_simple_network *this, 1280efe1bcfSAlexander Graf u32 *int_status, void **txbuf) 1290efe1bcfSAlexander Graf { 1300efe1bcfSAlexander Graf EFI_ENTRY("%p, %p, %p", this, int_status, txbuf); 1310efe1bcfSAlexander Graf 1320efe1bcfSAlexander Graf /* We send packets synchronously, so nothing is outstanding */ 1330efe1bcfSAlexander Graf if (int_status) 1340efe1bcfSAlexander Graf *int_status = 0; 1350efe1bcfSAlexander Graf if (txbuf) 1360efe1bcfSAlexander Graf *txbuf = new_tx_packet; 1370efe1bcfSAlexander Graf 1380efe1bcfSAlexander Graf new_tx_packet = NULL; 1390efe1bcfSAlexander Graf 1400efe1bcfSAlexander Graf return EFI_EXIT(EFI_SUCCESS); 1410efe1bcfSAlexander Graf } 1420efe1bcfSAlexander Graf 1430efe1bcfSAlexander Graf static efi_status_t EFIAPI efi_net_transmit(struct efi_simple_network *this, 1440efe1bcfSAlexander Graf ulong header_size, ulong buffer_size, void *buffer, 1450efe1bcfSAlexander Graf struct efi_mac_address *src_addr, 1460efe1bcfSAlexander Graf struct efi_mac_address *dest_addr, u16 *protocol) 1470efe1bcfSAlexander Graf { 1480efe1bcfSAlexander Graf EFI_ENTRY("%p, %lx, %lx, %p, %p, %p, %p", this, header_size, 1490efe1bcfSAlexander Graf buffer_size, buffer, src_addr, dest_addr, protocol); 1500efe1bcfSAlexander Graf 1510efe1bcfSAlexander Graf if (header_size) { 1520efe1bcfSAlexander Graf /* We would need to create the header if header_size != 0 */ 1530efe1bcfSAlexander Graf return EFI_EXIT(EFI_INVALID_PARAMETER); 1540efe1bcfSAlexander Graf } 1550efe1bcfSAlexander Graf 156712cd298SAlexander Graf #ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER 157712cd298SAlexander Graf /* Ethernet packets always fit, just bounce */ 158712cd298SAlexander Graf memcpy(efi_bounce_buffer, buffer, buffer_size); 159712cd298SAlexander Graf net_send_packet(efi_bounce_buffer, buffer_size); 160712cd298SAlexander Graf #else 1610efe1bcfSAlexander Graf net_send_packet(buffer, buffer_size); 162712cd298SAlexander Graf #endif 163712cd298SAlexander Graf 1640efe1bcfSAlexander Graf new_tx_packet = buffer; 1650efe1bcfSAlexander Graf 1660efe1bcfSAlexander Graf return EFI_EXIT(EFI_SUCCESS); 1670efe1bcfSAlexander Graf } 1680efe1bcfSAlexander Graf 1690efe1bcfSAlexander Graf static void efi_net_push(void *pkt, int len) 1700efe1bcfSAlexander Graf { 1710efe1bcfSAlexander Graf new_rx_packet = true; 1720efe1bcfSAlexander Graf } 1730efe1bcfSAlexander Graf 1740efe1bcfSAlexander Graf static efi_status_t EFIAPI efi_net_receive(struct efi_simple_network *this, 1750efe1bcfSAlexander Graf ulong *header_size, ulong *buffer_size, void *buffer, 1760efe1bcfSAlexander Graf struct efi_mac_address *src_addr, 1770efe1bcfSAlexander Graf struct efi_mac_address *dest_addr, u16 *protocol) 1780efe1bcfSAlexander Graf { 1790efe1bcfSAlexander Graf EFI_ENTRY("%p, %p, %p, %p, %p, %p, %p", this, header_size, 1800efe1bcfSAlexander Graf buffer_size, buffer, src_addr, dest_addr, protocol); 1810efe1bcfSAlexander Graf 1820efe1bcfSAlexander Graf push_packet = efi_net_push; 1830efe1bcfSAlexander Graf eth_rx(); 1840efe1bcfSAlexander Graf push_packet = NULL; 1850efe1bcfSAlexander Graf 1860efe1bcfSAlexander Graf if (!new_rx_packet) 1870efe1bcfSAlexander Graf return EFI_EXIT(EFI_NOT_READY); 1880efe1bcfSAlexander Graf 1890efe1bcfSAlexander Graf if (*buffer_size < net_rx_packet_len) { 1900efe1bcfSAlexander Graf /* Packet doesn't fit, try again with bigger buf */ 1910efe1bcfSAlexander Graf *buffer_size = net_rx_packet_len; 1920efe1bcfSAlexander Graf return EFI_EXIT(EFI_BUFFER_TOO_SMALL); 1930efe1bcfSAlexander Graf } 1940efe1bcfSAlexander Graf 1950efe1bcfSAlexander Graf memcpy(buffer, net_rx_packet, net_rx_packet_len); 1960efe1bcfSAlexander Graf *buffer_size = net_rx_packet_len; 1970efe1bcfSAlexander Graf new_rx_packet = false; 1980efe1bcfSAlexander Graf 1990efe1bcfSAlexander Graf return EFI_EXIT(EFI_SUCCESS); 2000efe1bcfSAlexander Graf } 2010efe1bcfSAlexander Graf 202e275458cSSimon Glass static efi_status_t EFIAPI efi_net_open_dp(void *handle, efi_guid_t *protocol, 2030efe1bcfSAlexander Graf void **protocol_interface, void *agent_handle, 2040efe1bcfSAlexander Graf void *controller_handle, uint32_t attributes) 2050efe1bcfSAlexander Graf { 2060efe1bcfSAlexander Graf struct efi_simple_network *net = handle; 2070efe1bcfSAlexander Graf struct efi_net_obj *netobj = container_of(net, struct efi_net_obj, net); 2080efe1bcfSAlexander Graf 209*d7608abaSOleksandr Tymoshenko *protocol_interface = &netobj->dp_mac; 2100efe1bcfSAlexander Graf 2110efe1bcfSAlexander Graf return EFI_SUCCESS; 2120efe1bcfSAlexander Graf } 2130efe1bcfSAlexander Graf 214e275458cSSimon Glass static efi_status_t EFIAPI efi_net_open_pxe(void *handle, efi_guid_t *protocol, 2150efe1bcfSAlexander Graf void **protocol_interface, void *agent_handle, 2160efe1bcfSAlexander Graf void *controller_handle, uint32_t attributes) 2170efe1bcfSAlexander Graf { 2180efe1bcfSAlexander Graf struct efi_simple_network *net = handle; 2190efe1bcfSAlexander Graf struct efi_net_obj *netobj = container_of(net, struct efi_net_obj, net); 2200efe1bcfSAlexander Graf 2210efe1bcfSAlexander Graf *protocol_interface = &netobj->pxe; 2220efe1bcfSAlexander Graf 2230efe1bcfSAlexander Graf return EFI_SUCCESS; 2240efe1bcfSAlexander Graf } 2250efe1bcfSAlexander Graf 2260efe1bcfSAlexander Graf void efi_net_set_dhcp_ack(void *pkt, int len) 2270efe1bcfSAlexander Graf { 2280efe1bcfSAlexander Graf int maxsize = sizeof(*dhcp_ack); 2290efe1bcfSAlexander Graf 2300efe1bcfSAlexander Graf if (!dhcp_ack) 2310efe1bcfSAlexander Graf dhcp_ack = malloc(maxsize); 2320efe1bcfSAlexander Graf 2330efe1bcfSAlexander Graf memcpy(dhcp_ack, pkt, min(len, maxsize)); 2340efe1bcfSAlexander Graf } 2350efe1bcfSAlexander Graf 2360efe1bcfSAlexander Graf /* This gets called from do_bootefi_exec(). */ 2370efe1bcfSAlexander Graf int efi_net_register(void **handle) 2380efe1bcfSAlexander Graf { 2390efe1bcfSAlexander Graf struct efi_net_obj *netobj; 240*d7608abaSOleksandr Tymoshenko struct efi_device_path_mac_addr dp_net = { 241*d7608abaSOleksandr Tymoshenko .dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE, 242*d7608abaSOleksandr Tymoshenko .dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR, 2430efe1bcfSAlexander Graf .dp.length = sizeof(dp_net), 2440efe1bcfSAlexander Graf }; 2450efe1bcfSAlexander Graf struct efi_device_path_file_path dp_end = { 2460efe1bcfSAlexander Graf .dp.type = DEVICE_PATH_TYPE_END, 2470efe1bcfSAlexander Graf .dp.sub_type = DEVICE_PATH_SUB_TYPE_END, 2480efe1bcfSAlexander Graf .dp.length = sizeof(dp_end), 2490efe1bcfSAlexander Graf }; 2500efe1bcfSAlexander Graf 2510efe1bcfSAlexander Graf if (!eth_get_dev()) { 2520efe1bcfSAlexander Graf /* No eth device active, don't expose any */ 2530efe1bcfSAlexander Graf return 0; 2540efe1bcfSAlexander Graf } 2550efe1bcfSAlexander Graf 2560efe1bcfSAlexander Graf /* We only expose the "active" eth device, so one is enough */ 2570efe1bcfSAlexander Graf netobj = calloc(1, sizeof(*netobj)); 2580efe1bcfSAlexander Graf 2590efe1bcfSAlexander Graf /* Fill in object data */ 2600efe1bcfSAlexander Graf netobj->parent.protocols[0].guid = &efi_net_guid; 2610efe1bcfSAlexander Graf netobj->parent.protocols[0].open = efi_return_handle; 2620efe1bcfSAlexander Graf netobj->parent.protocols[1].guid = &efi_guid_device_path; 2630efe1bcfSAlexander Graf netobj->parent.protocols[1].open = efi_net_open_dp; 2640efe1bcfSAlexander Graf netobj->parent.protocols[2].guid = &efi_pxe_guid; 2650efe1bcfSAlexander Graf netobj->parent.protocols[2].open = efi_net_open_pxe; 2660efe1bcfSAlexander Graf netobj->parent.handle = &netobj->net; 2670efe1bcfSAlexander Graf netobj->net.start = efi_net_start; 2680efe1bcfSAlexander Graf netobj->net.stop = efi_net_stop; 2690efe1bcfSAlexander Graf netobj->net.initialize = efi_net_initialize; 2700efe1bcfSAlexander Graf netobj->net.reset = efi_net_reset; 2710efe1bcfSAlexander Graf netobj->net.shutdown = efi_net_shutdown; 2720efe1bcfSAlexander Graf netobj->net.receive_filters = efi_net_receive_filters; 2730efe1bcfSAlexander Graf netobj->net.station_address = efi_net_station_address; 2740efe1bcfSAlexander Graf netobj->net.statistics = efi_net_statistics; 2750efe1bcfSAlexander Graf netobj->net.mcastiptomac = efi_net_mcastiptomac; 2760efe1bcfSAlexander Graf netobj->net.nvdata = efi_net_nvdata; 2770efe1bcfSAlexander Graf netobj->net.get_status = efi_net_get_status; 2780efe1bcfSAlexander Graf netobj->net.transmit = efi_net_transmit; 2790efe1bcfSAlexander Graf netobj->net.receive = efi_net_receive; 2800efe1bcfSAlexander Graf netobj->net.mode = &netobj->net_mode; 2810efe1bcfSAlexander Graf netobj->net_mode.state = EFI_NETWORK_STARTED; 282*d7608abaSOleksandr Tymoshenko netobj->dp_mac = dp_net; 283*d7608abaSOleksandr Tymoshenko netobj->dp_end = dp_end; 284*d7608abaSOleksandr Tymoshenko memcpy(netobj->dp_mac.mac.addr, eth_get_ethaddr(), 6); 2850efe1bcfSAlexander Graf memcpy(netobj->net_mode.current_address.mac_addr, eth_get_ethaddr(), 6); 2860efe1bcfSAlexander Graf netobj->net_mode.max_packet_size = PKTSIZE; 2870efe1bcfSAlexander Graf 2880efe1bcfSAlexander Graf netobj->pxe.mode = &netobj->pxe_mode; 2890efe1bcfSAlexander Graf if (dhcp_ack) 2900efe1bcfSAlexander Graf netobj->pxe_mode.dhcp_ack = *dhcp_ack; 2910efe1bcfSAlexander Graf 2920efe1bcfSAlexander Graf /* Hook net up to the device list */ 2930efe1bcfSAlexander Graf list_add_tail(&netobj->parent.link, &efi_obj_list); 2940efe1bcfSAlexander Graf 2950efe1bcfSAlexander Graf if (handle) 2960efe1bcfSAlexander Graf *handle = &netobj->net; 2970efe1bcfSAlexander Graf 2980efe1bcfSAlexander Graf return 0; 2990efe1bcfSAlexander Graf } 300