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 */ 300efe1bcfSAlexander Graf struct efi_device_path_file_path dp[2]; 310efe1bcfSAlexander Graf /* PXE struct to transmit dhcp data */ 320efe1bcfSAlexander Graf struct efi_pxe pxe; 330efe1bcfSAlexander Graf struct efi_pxe_mode pxe_mode; 340efe1bcfSAlexander Graf }; 350efe1bcfSAlexander Graf 360efe1bcfSAlexander Graf static efi_status_t EFIAPI efi_net_start(struct efi_simple_network *this) 370efe1bcfSAlexander Graf { 380efe1bcfSAlexander Graf EFI_ENTRY("%p", this); 390efe1bcfSAlexander Graf 400efe1bcfSAlexander Graf return EFI_EXIT(EFI_SUCCESS); 410efe1bcfSAlexander Graf } 420efe1bcfSAlexander Graf 430efe1bcfSAlexander Graf static efi_status_t EFIAPI efi_net_stop(struct efi_simple_network *this) 440efe1bcfSAlexander Graf { 450efe1bcfSAlexander Graf EFI_ENTRY("%p", this); 460efe1bcfSAlexander Graf 470efe1bcfSAlexander Graf return EFI_EXIT(EFI_SUCCESS); 480efe1bcfSAlexander Graf } 490efe1bcfSAlexander Graf 500efe1bcfSAlexander Graf static efi_status_t EFIAPI efi_net_initialize(struct efi_simple_network *this, 510efe1bcfSAlexander Graf ulong extra_rx, ulong extra_tx) 520efe1bcfSAlexander Graf { 530efe1bcfSAlexander Graf EFI_ENTRY("%p, %lx, %lx", this, extra_rx, extra_tx); 540efe1bcfSAlexander Graf 550efe1bcfSAlexander Graf eth_init(); 560efe1bcfSAlexander Graf 570efe1bcfSAlexander Graf return EFI_EXIT(EFI_SUCCESS); 580efe1bcfSAlexander Graf } 590efe1bcfSAlexander Graf 600efe1bcfSAlexander Graf static efi_status_t EFIAPI efi_net_reset(struct efi_simple_network *this, 610efe1bcfSAlexander Graf int extended_verification) 620efe1bcfSAlexander Graf { 630efe1bcfSAlexander Graf EFI_ENTRY("%p, %x", this, extended_verification); 640efe1bcfSAlexander Graf 650efe1bcfSAlexander Graf return EFI_EXIT(EFI_SUCCESS); 660efe1bcfSAlexander Graf } 670efe1bcfSAlexander Graf 680efe1bcfSAlexander Graf static efi_status_t EFIAPI efi_net_shutdown(struct efi_simple_network *this) 690efe1bcfSAlexander Graf { 700efe1bcfSAlexander Graf EFI_ENTRY("%p", this); 710efe1bcfSAlexander Graf 720efe1bcfSAlexander Graf return EFI_EXIT(EFI_SUCCESS); 730efe1bcfSAlexander Graf } 740efe1bcfSAlexander Graf 750efe1bcfSAlexander Graf static efi_status_t EFIAPI efi_net_receive_filters( 760efe1bcfSAlexander Graf struct efi_simple_network *this, u32 enable, u32 disable, 770efe1bcfSAlexander Graf int reset_mcast_filter, ulong mcast_filter_count, 780efe1bcfSAlexander Graf struct efi_mac_address *mcast_filter) 790efe1bcfSAlexander Graf { 800efe1bcfSAlexander Graf EFI_ENTRY("%p, %x, %x, %x, %lx, %p", this, enable, disable, 810efe1bcfSAlexander Graf reset_mcast_filter, mcast_filter_count, mcast_filter); 820efe1bcfSAlexander Graf 830efe1bcfSAlexander Graf /* XXX Do we care? */ 840efe1bcfSAlexander Graf 850efe1bcfSAlexander Graf return EFI_EXIT(EFI_SUCCESS); 860efe1bcfSAlexander Graf } 870efe1bcfSAlexander Graf 880efe1bcfSAlexander Graf static efi_status_t EFIAPI efi_net_station_address( 890efe1bcfSAlexander Graf struct efi_simple_network *this, int reset, 900efe1bcfSAlexander Graf struct efi_mac_address *new_mac) 910efe1bcfSAlexander Graf { 920efe1bcfSAlexander Graf EFI_ENTRY("%p, %x, %p", this, reset, new_mac); 930efe1bcfSAlexander Graf 940efe1bcfSAlexander Graf return EFI_EXIT(EFI_INVALID_PARAMETER); 950efe1bcfSAlexander Graf } 960efe1bcfSAlexander Graf 970efe1bcfSAlexander Graf static efi_status_t EFIAPI efi_net_statistics(struct efi_simple_network *this, 980efe1bcfSAlexander Graf int reset, ulong *stat_size, 990efe1bcfSAlexander Graf void *stat_table) 1000efe1bcfSAlexander Graf { 1010efe1bcfSAlexander Graf EFI_ENTRY("%p, %x, %p, %p", this, reset, stat_size, stat_table); 1020efe1bcfSAlexander Graf 1030efe1bcfSAlexander Graf return EFI_EXIT(EFI_INVALID_PARAMETER); 1040efe1bcfSAlexander Graf } 1050efe1bcfSAlexander Graf 1060efe1bcfSAlexander Graf static efi_status_t EFIAPI efi_net_mcastiptomac(struct efi_simple_network *this, 1070efe1bcfSAlexander Graf int ipv6, 1080efe1bcfSAlexander Graf struct efi_ip_address *ip, 1090efe1bcfSAlexander Graf struct efi_mac_address *mac) 1100efe1bcfSAlexander Graf { 1110efe1bcfSAlexander Graf EFI_ENTRY("%p, %x, %p, %p", this, ipv6, ip, mac); 1120efe1bcfSAlexander Graf 1130efe1bcfSAlexander Graf return EFI_EXIT(EFI_INVALID_PARAMETER); 1140efe1bcfSAlexander Graf } 1150efe1bcfSAlexander Graf 1160efe1bcfSAlexander Graf static efi_status_t EFIAPI efi_net_nvdata(struct efi_simple_network *this, 1170efe1bcfSAlexander Graf int read_write, ulong offset, 1180efe1bcfSAlexander Graf ulong buffer_size, char *buffer) 1190efe1bcfSAlexander Graf { 1200efe1bcfSAlexander Graf EFI_ENTRY("%p, %x, %lx, %lx, %p", this, read_write, offset, buffer_size, 1210efe1bcfSAlexander Graf buffer); 1220efe1bcfSAlexander Graf 1230efe1bcfSAlexander Graf return EFI_EXIT(EFI_INVALID_PARAMETER); 1240efe1bcfSAlexander Graf } 1250efe1bcfSAlexander Graf 1260efe1bcfSAlexander Graf static efi_status_t EFIAPI efi_net_get_status(struct efi_simple_network *this, 1270efe1bcfSAlexander Graf u32 *int_status, void **txbuf) 1280efe1bcfSAlexander Graf { 1290efe1bcfSAlexander Graf EFI_ENTRY("%p, %p, %p", this, int_status, txbuf); 1300efe1bcfSAlexander Graf 1310efe1bcfSAlexander Graf /* We send packets synchronously, so nothing is outstanding */ 1320efe1bcfSAlexander Graf if (int_status) 1330efe1bcfSAlexander Graf *int_status = 0; 1340efe1bcfSAlexander Graf if (txbuf) 1350efe1bcfSAlexander Graf *txbuf = new_tx_packet; 1360efe1bcfSAlexander Graf 1370efe1bcfSAlexander Graf new_tx_packet = NULL; 1380efe1bcfSAlexander Graf 1390efe1bcfSAlexander Graf return EFI_EXIT(EFI_SUCCESS); 1400efe1bcfSAlexander Graf } 1410efe1bcfSAlexander Graf 1420efe1bcfSAlexander Graf static efi_status_t EFIAPI efi_net_transmit(struct efi_simple_network *this, 1430efe1bcfSAlexander Graf ulong header_size, ulong buffer_size, void *buffer, 1440efe1bcfSAlexander Graf struct efi_mac_address *src_addr, 1450efe1bcfSAlexander Graf struct efi_mac_address *dest_addr, u16 *protocol) 1460efe1bcfSAlexander Graf { 1470efe1bcfSAlexander Graf EFI_ENTRY("%p, %lx, %lx, %p, %p, %p, %p", this, header_size, 1480efe1bcfSAlexander Graf buffer_size, buffer, src_addr, dest_addr, protocol); 1490efe1bcfSAlexander Graf 1500efe1bcfSAlexander Graf if (header_size) { 1510efe1bcfSAlexander Graf /* We would need to create the header if header_size != 0 */ 1520efe1bcfSAlexander Graf return EFI_EXIT(EFI_INVALID_PARAMETER); 1530efe1bcfSAlexander Graf } 1540efe1bcfSAlexander Graf 155712cd298SAlexander Graf #ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER 156712cd298SAlexander Graf /* Ethernet packets always fit, just bounce */ 157712cd298SAlexander Graf memcpy(efi_bounce_buffer, buffer, buffer_size); 158712cd298SAlexander Graf net_send_packet(efi_bounce_buffer, buffer_size); 159712cd298SAlexander Graf #else 1600efe1bcfSAlexander Graf net_send_packet(buffer, buffer_size); 161712cd298SAlexander Graf #endif 162712cd298SAlexander Graf 1630efe1bcfSAlexander Graf new_tx_packet = buffer; 1640efe1bcfSAlexander Graf 1650efe1bcfSAlexander Graf return EFI_EXIT(EFI_SUCCESS); 1660efe1bcfSAlexander Graf } 1670efe1bcfSAlexander Graf 1680efe1bcfSAlexander Graf static void efi_net_push(void *pkt, int len) 1690efe1bcfSAlexander Graf { 1700efe1bcfSAlexander Graf new_rx_packet = true; 1710efe1bcfSAlexander Graf } 1720efe1bcfSAlexander Graf 1730efe1bcfSAlexander Graf static efi_status_t EFIAPI efi_net_receive(struct efi_simple_network *this, 1740efe1bcfSAlexander Graf ulong *header_size, ulong *buffer_size, void *buffer, 1750efe1bcfSAlexander Graf struct efi_mac_address *src_addr, 1760efe1bcfSAlexander Graf struct efi_mac_address *dest_addr, u16 *protocol) 1770efe1bcfSAlexander Graf { 1780efe1bcfSAlexander Graf EFI_ENTRY("%p, %p, %p, %p, %p, %p, %p", this, header_size, 1790efe1bcfSAlexander Graf buffer_size, buffer, src_addr, dest_addr, protocol); 1800efe1bcfSAlexander Graf 1810efe1bcfSAlexander Graf push_packet = efi_net_push; 1820efe1bcfSAlexander Graf eth_rx(); 1830efe1bcfSAlexander Graf push_packet = NULL; 1840efe1bcfSAlexander Graf 1850efe1bcfSAlexander Graf if (!new_rx_packet) 1860efe1bcfSAlexander Graf return EFI_EXIT(EFI_NOT_READY); 1870efe1bcfSAlexander Graf 1880efe1bcfSAlexander Graf if (*buffer_size < net_rx_packet_len) { 1890efe1bcfSAlexander Graf /* Packet doesn't fit, try again with bigger buf */ 1900efe1bcfSAlexander Graf *buffer_size = net_rx_packet_len; 1910efe1bcfSAlexander Graf return EFI_EXIT(EFI_BUFFER_TOO_SMALL); 1920efe1bcfSAlexander Graf } 1930efe1bcfSAlexander Graf 1940efe1bcfSAlexander Graf memcpy(buffer, net_rx_packet, net_rx_packet_len); 1950efe1bcfSAlexander Graf *buffer_size = net_rx_packet_len; 1960efe1bcfSAlexander Graf new_rx_packet = false; 1970efe1bcfSAlexander Graf 1980efe1bcfSAlexander Graf return EFI_EXIT(EFI_SUCCESS); 1990efe1bcfSAlexander Graf } 2000efe1bcfSAlexander Graf 201*e275458cSSimon Glass static efi_status_t EFIAPI efi_net_open_dp(void *handle, efi_guid_t *protocol, 2020efe1bcfSAlexander Graf void **protocol_interface, void *agent_handle, 2030efe1bcfSAlexander Graf void *controller_handle, uint32_t attributes) 2040efe1bcfSAlexander Graf { 2050efe1bcfSAlexander Graf struct efi_simple_network *net = handle; 2060efe1bcfSAlexander Graf struct efi_net_obj *netobj = container_of(net, struct efi_net_obj, net); 2070efe1bcfSAlexander Graf 2080efe1bcfSAlexander Graf *protocol_interface = netobj->dp; 2090efe1bcfSAlexander Graf 2100efe1bcfSAlexander Graf return EFI_SUCCESS; 2110efe1bcfSAlexander Graf } 2120efe1bcfSAlexander Graf 213*e275458cSSimon Glass static efi_status_t EFIAPI efi_net_open_pxe(void *handle, efi_guid_t *protocol, 2140efe1bcfSAlexander Graf void **protocol_interface, void *agent_handle, 2150efe1bcfSAlexander Graf void *controller_handle, uint32_t attributes) 2160efe1bcfSAlexander Graf { 2170efe1bcfSAlexander Graf struct efi_simple_network *net = handle; 2180efe1bcfSAlexander Graf struct efi_net_obj *netobj = container_of(net, struct efi_net_obj, net); 2190efe1bcfSAlexander Graf 2200efe1bcfSAlexander Graf *protocol_interface = &netobj->pxe; 2210efe1bcfSAlexander Graf 2220efe1bcfSAlexander Graf return EFI_SUCCESS; 2230efe1bcfSAlexander Graf } 2240efe1bcfSAlexander Graf 2250efe1bcfSAlexander Graf void efi_net_set_dhcp_ack(void *pkt, int len) 2260efe1bcfSAlexander Graf { 2270efe1bcfSAlexander Graf int maxsize = sizeof(*dhcp_ack); 2280efe1bcfSAlexander Graf 2290efe1bcfSAlexander Graf if (!dhcp_ack) 2300efe1bcfSAlexander Graf dhcp_ack = malloc(maxsize); 2310efe1bcfSAlexander Graf 2320efe1bcfSAlexander Graf memcpy(dhcp_ack, pkt, min(len, maxsize)); 2330efe1bcfSAlexander Graf } 2340efe1bcfSAlexander Graf 2350efe1bcfSAlexander Graf /* This gets called from do_bootefi_exec(). */ 2360efe1bcfSAlexander Graf int efi_net_register(void **handle) 2370efe1bcfSAlexander Graf { 2380efe1bcfSAlexander Graf struct efi_net_obj *netobj; 2390efe1bcfSAlexander Graf struct efi_device_path_file_path dp_net = { 2400efe1bcfSAlexander Graf .dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE, 2410efe1bcfSAlexander Graf .dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH, 2420efe1bcfSAlexander Graf .dp.length = sizeof(dp_net), 2430efe1bcfSAlexander Graf .str = { 'N', 'e', 't' }, 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; 2820efe1bcfSAlexander Graf netobj->dp[0] = dp_net; 2830efe1bcfSAlexander Graf netobj->dp[1] = dp_end; 2840efe1bcfSAlexander Graf memcpy(netobj->net_mode.current_address.mac_addr, eth_get_ethaddr(), 6); 2850efe1bcfSAlexander Graf netobj->net_mode.max_packet_size = PKTSIZE; 2860efe1bcfSAlexander Graf 2870efe1bcfSAlexander Graf netobj->pxe.mode = &netobj->pxe_mode; 2880efe1bcfSAlexander Graf if (dhcp_ack) 2890efe1bcfSAlexander Graf netobj->pxe_mode.dhcp_ack = *dhcp_ack; 2900efe1bcfSAlexander Graf 2910efe1bcfSAlexander Graf /* Hook net up to the device list */ 2920efe1bcfSAlexander Graf list_add_tail(&netobj->parent.link, &efi_obj_list); 2930efe1bcfSAlexander Graf 2940efe1bcfSAlexander Graf if (handle) 2950efe1bcfSAlexander Graf *handle = &netobj->net; 2960efe1bcfSAlexander Graf 2970efe1bcfSAlexander Graf return 0; 2980efe1bcfSAlexander Graf } 299