1*0efe1bcfSAlexander Graf /* 2*0efe1bcfSAlexander Graf * EFI application network access support 3*0efe1bcfSAlexander Graf * 4*0efe1bcfSAlexander Graf * Copyright (c) 2016 Alexander Graf 5*0efe1bcfSAlexander Graf * 6*0efe1bcfSAlexander Graf * SPDX-License-Identifier: GPL-2.0+ 7*0efe1bcfSAlexander Graf */ 8*0efe1bcfSAlexander Graf 9*0efe1bcfSAlexander Graf #include <common.h> 10*0efe1bcfSAlexander Graf #include <efi_loader.h> 11*0efe1bcfSAlexander Graf #include <inttypes.h> 12*0efe1bcfSAlexander Graf #include <lcd.h> 13*0efe1bcfSAlexander Graf #include <malloc.h> 14*0efe1bcfSAlexander Graf 15*0efe1bcfSAlexander Graf DECLARE_GLOBAL_DATA_PTR; 16*0efe1bcfSAlexander Graf 17*0efe1bcfSAlexander Graf static const efi_guid_t efi_net_guid = EFI_SIMPLE_NETWORK_GUID; 18*0efe1bcfSAlexander Graf static const efi_guid_t efi_pxe_guid = EFI_PXE_GUID; 19*0efe1bcfSAlexander Graf static struct efi_pxe_packet *dhcp_ack; 20*0efe1bcfSAlexander Graf static bool new_rx_packet; 21*0efe1bcfSAlexander Graf static void *new_tx_packet; 22*0efe1bcfSAlexander Graf 23*0efe1bcfSAlexander Graf struct efi_net_obj { 24*0efe1bcfSAlexander Graf /* Generic EFI object parent class data */ 25*0efe1bcfSAlexander Graf struct efi_object parent; 26*0efe1bcfSAlexander Graf /* EFI Interface callback struct for network */ 27*0efe1bcfSAlexander Graf struct efi_simple_network net; 28*0efe1bcfSAlexander Graf struct efi_simple_network_mode net_mode; 29*0efe1bcfSAlexander Graf /* Device path to the network adapter */ 30*0efe1bcfSAlexander Graf struct efi_device_path_file_path dp[2]; 31*0efe1bcfSAlexander Graf /* PXE struct to transmit dhcp data */ 32*0efe1bcfSAlexander Graf struct efi_pxe pxe; 33*0efe1bcfSAlexander Graf struct efi_pxe_mode pxe_mode; 34*0efe1bcfSAlexander Graf }; 35*0efe1bcfSAlexander Graf 36*0efe1bcfSAlexander Graf static efi_status_t EFIAPI efi_net_start(struct efi_simple_network *this) 37*0efe1bcfSAlexander Graf { 38*0efe1bcfSAlexander Graf EFI_ENTRY("%p", this); 39*0efe1bcfSAlexander Graf 40*0efe1bcfSAlexander Graf return EFI_EXIT(EFI_SUCCESS); 41*0efe1bcfSAlexander Graf } 42*0efe1bcfSAlexander Graf 43*0efe1bcfSAlexander Graf static efi_status_t EFIAPI efi_net_stop(struct efi_simple_network *this) 44*0efe1bcfSAlexander Graf { 45*0efe1bcfSAlexander Graf EFI_ENTRY("%p", this); 46*0efe1bcfSAlexander Graf 47*0efe1bcfSAlexander Graf return EFI_EXIT(EFI_SUCCESS); 48*0efe1bcfSAlexander Graf } 49*0efe1bcfSAlexander Graf 50*0efe1bcfSAlexander Graf static efi_status_t EFIAPI efi_net_initialize(struct efi_simple_network *this, 51*0efe1bcfSAlexander Graf ulong extra_rx, ulong extra_tx) 52*0efe1bcfSAlexander Graf { 53*0efe1bcfSAlexander Graf EFI_ENTRY("%p, %lx, %lx", this, extra_rx, extra_tx); 54*0efe1bcfSAlexander Graf 55*0efe1bcfSAlexander Graf eth_init(); 56*0efe1bcfSAlexander Graf 57*0efe1bcfSAlexander Graf return EFI_EXIT(EFI_SUCCESS); 58*0efe1bcfSAlexander Graf } 59*0efe1bcfSAlexander Graf 60*0efe1bcfSAlexander Graf static efi_status_t EFIAPI efi_net_reset(struct efi_simple_network *this, 61*0efe1bcfSAlexander Graf int extended_verification) 62*0efe1bcfSAlexander Graf { 63*0efe1bcfSAlexander Graf EFI_ENTRY("%p, %x", this, extended_verification); 64*0efe1bcfSAlexander Graf 65*0efe1bcfSAlexander Graf return EFI_EXIT(EFI_SUCCESS); 66*0efe1bcfSAlexander Graf } 67*0efe1bcfSAlexander Graf 68*0efe1bcfSAlexander Graf static efi_status_t EFIAPI efi_net_shutdown(struct efi_simple_network *this) 69*0efe1bcfSAlexander Graf { 70*0efe1bcfSAlexander Graf EFI_ENTRY("%p", this); 71*0efe1bcfSAlexander Graf 72*0efe1bcfSAlexander Graf return EFI_EXIT(EFI_SUCCESS); 73*0efe1bcfSAlexander Graf } 74*0efe1bcfSAlexander Graf 75*0efe1bcfSAlexander Graf static efi_status_t EFIAPI efi_net_receive_filters( 76*0efe1bcfSAlexander Graf struct efi_simple_network *this, u32 enable, u32 disable, 77*0efe1bcfSAlexander Graf int reset_mcast_filter, ulong mcast_filter_count, 78*0efe1bcfSAlexander Graf struct efi_mac_address *mcast_filter) 79*0efe1bcfSAlexander Graf { 80*0efe1bcfSAlexander Graf EFI_ENTRY("%p, %x, %x, %x, %lx, %p", this, enable, disable, 81*0efe1bcfSAlexander Graf reset_mcast_filter, mcast_filter_count, mcast_filter); 82*0efe1bcfSAlexander Graf 83*0efe1bcfSAlexander Graf /* XXX Do we care? */ 84*0efe1bcfSAlexander Graf 85*0efe1bcfSAlexander Graf return EFI_EXIT(EFI_SUCCESS); 86*0efe1bcfSAlexander Graf } 87*0efe1bcfSAlexander Graf 88*0efe1bcfSAlexander Graf static efi_status_t EFIAPI efi_net_station_address( 89*0efe1bcfSAlexander Graf struct efi_simple_network *this, int reset, 90*0efe1bcfSAlexander Graf struct efi_mac_address *new_mac) 91*0efe1bcfSAlexander Graf { 92*0efe1bcfSAlexander Graf EFI_ENTRY("%p, %x, %p", this, reset, new_mac); 93*0efe1bcfSAlexander Graf 94*0efe1bcfSAlexander Graf return EFI_EXIT(EFI_INVALID_PARAMETER); 95*0efe1bcfSAlexander Graf } 96*0efe1bcfSAlexander Graf 97*0efe1bcfSAlexander Graf static efi_status_t EFIAPI efi_net_statistics(struct efi_simple_network *this, 98*0efe1bcfSAlexander Graf int reset, ulong *stat_size, 99*0efe1bcfSAlexander Graf void *stat_table) 100*0efe1bcfSAlexander Graf { 101*0efe1bcfSAlexander Graf EFI_ENTRY("%p, %x, %p, %p", this, reset, stat_size, stat_table); 102*0efe1bcfSAlexander Graf 103*0efe1bcfSAlexander Graf return EFI_EXIT(EFI_INVALID_PARAMETER); 104*0efe1bcfSAlexander Graf } 105*0efe1bcfSAlexander Graf 106*0efe1bcfSAlexander Graf static efi_status_t EFIAPI efi_net_mcastiptomac(struct efi_simple_network *this, 107*0efe1bcfSAlexander Graf int ipv6, 108*0efe1bcfSAlexander Graf struct efi_ip_address *ip, 109*0efe1bcfSAlexander Graf struct efi_mac_address *mac) 110*0efe1bcfSAlexander Graf { 111*0efe1bcfSAlexander Graf EFI_ENTRY("%p, %x, %p, %p", this, ipv6, ip, mac); 112*0efe1bcfSAlexander Graf 113*0efe1bcfSAlexander Graf return EFI_EXIT(EFI_INVALID_PARAMETER); 114*0efe1bcfSAlexander Graf } 115*0efe1bcfSAlexander Graf 116*0efe1bcfSAlexander Graf static efi_status_t EFIAPI efi_net_nvdata(struct efi_simple_network *this, 117*0efe1bcfSAlexander Graf int read_write, ulong offset, 118*0efe1bcfSAlexander Graf ulong buffer_size, char *buffer) 119*0efe1bcfSAlexander Graf { 120*0efe1bcfSAlexander Graf EFI_ENTRY("%p, %x, %lx, %lx, %p", this, read_write, offset, buffer_size, 121*0efe1bcfSAlexander Graf buffer); 122*0efe1bcfSAlexander Graf 123*0efe1bcfSAlexander Graf return EFI_EXIT(EFI_INVALID_PARAMETER); 124*0efe1bcfSAlexander Graf } 125*0efe1bcfSAlexander Graf 126*0efe1bcfSAlexander Graf static efi_status_t EFIAPI efi_net_get_status(struct efi_simple_network *this, 127*0efe1bcfSAlexander Graf u32 *int_status, void **txbuf) 128*0efe1bcfSAlexander Graf { 129*0efe1bcfSAlexander Graf EFI_ENTRY("%p, %p, %p", this, int_status, txbuf); 130*0efe1bcfSAlexander Graf 131*0efe1bcfSAlexander Graf /* We send packets synchronously, so nothing is outstanding */ 132*0efe1bcfSAlexander Graf if (int_status) 133*0efe1bcfSAlexander Graf *int_status = 0; 134*0efe1bcfSAlexander Graf if (txbuf) 135*0efe1bcfSAlexander Graf *txbuf = new_tx_packet; 136*0efe1bcfSAlexander Graf 137*0efe1bcfSAlexander Graf new_tx_packet = NULL; 138*0efe1bcfSAlexander Graf 139*0efe1bcfSAlexander Graf return EFI_EXIT(EFI_SUCCESS); 140*0efe1bcfSAlexander Graf } 141*0efe1bcfSAlexander Graf 142*0efe1bcfSAlexander Graf static efi_status_t EFIAPI efi_net_transmit(struct efi_simple_network *this, 143*0efe1bcfSAlexander Graf ulong header_size, ulong buffer_size, void *buffer, 144*0efe1bcfSAlexander Graf struct efi_mac_address *src_addr, 145*0efe1bcfSAlexander Graf struct efi_mac_address *dest_addr, u16 *protocol) 146*0efe1bcfSAlexander Graf { 147*0efe1bcfSAlexander Graf EFI_ENTRY("%p, %lx, %lx, %p, %p, %p, %p", this, header_size, 148*0efe1bcfSAlexander Graf buffer_size, buffer, src_addr, dest_addr, protocol); 149*0efe1bcfSAlexander Graf 150*0efe1bcfSAlexander Graf if (header_size) { 151*0efe1bcfSAlexander Graf /* We would need to create the header if header_size != 0 */ 152*0efe1bcfSAlexander Graf return EFI_EXIT(EFI_INVALID_PARAMETER); 153*0efe1bcfSAlexander Graf } 154*0efe1bcfSAlexander Graf 155*0efe1bcfSAlexander Graf net_send_packet(buffer, buffer_size); 156*0efe1bcfSAlexander Graf new_tx_packet = buffer; 157*0efe1bcfSAlexander Graf 158*0efe1bcfSAlexander Graf return EFI_EXIT(EFI_SUCCESS); 159*0efe1bcfSAlexander Graf } 160*0efe1bcfSAlexander Graf 161*0efe1bcfSAlexander Graf static void efi_net_push(void *pkt, int len) 162*0efe1bcfSAlexander Graf { 163*0efe1bcfSAlexander Graf new_rx_packet = true; 164*0efe1bcfSAlexander Graf } 165*0efe1bcfSAlexander Graf 166*0efe1bcfSAlexander Graf static efi_status_t EFIAPI efi_net_receive(struct efi_simple_network *this, 167*0efe1bcfSAlexander Graf ulong *header_size, ulong *buffer_size, void *buffer, 168*0efe1bcfSAlexander Graf struct efi_mac_address *src_addr, 169*0efe1bcfSAlexander Graf struct efi_mac_address *dest_addr, u16 *protocol) 170*0efe1bcfSAlexander Graf { 171*0efe1bcfSAlexander Graf EFI_ENTRY("%p, %p, %p, %p, %p, %p, %p", this, header_size, 172*0efe1bcfSAlexander Graf buffer_size, buffer, src_addr, dest_addr, protocol); 173*0efe1bcfSAlexander Graf 174*0efe1bcfSAlexander Graf push_packet = efi_net_push; 175*0efe1bcfSAlexander Graf eth_rx(); 176*0efe1bcfSAlexander Graf push_packet = NULL; 177*0efe1bcfSAlexander Graf 178*0efe1bcfSAlexander Graf if (!new_rx_packet) 179*0efe1bcfSAlexander Graf return EFI_EXIT(EFI_NOT_READY); 180*0efe1bcfSAlexander Graf 181*0efe1bcfSAlexander Graf if (*buffer_size < net_rx_packet_len) { 182*0efe1bcfSAlexander Graf /* Packet doesn't fit, try again with bigger buf */ 183*0efe1bcfSAlexander Graf *buffer_size = net_rx_packet_len; 184*0efe1bcfSAlexander Graf return EFI_EXIT(EFI_BUFFER_TOO_SMALL); 185*0efe1bcfSAlexander Graf } 186*0efe1bcfSAlexander Graf 187*0efe1bcfSAlexander Graf memcpy(buffer, net_rx_packet, net_rx_packet_len); 188*0efe1bcfSAlexander Graf *buffer_size = net_rx_packet_len; 189*0efe1bcfSAlexander Graf new_rx_packet = false; 190*0efe1bcfSAlexander Graf 191*0efe1bcfSAlexander Graf return EFI_EXIT(EFI_SUCCESS); 192*0efe1bcfSAlexander Graf } 193*0efe1bcfSAlexander Graf 194*0efe1bcfSAlexander Graf static efi_status_t efi_net_open_dp(void *handle, efi_guid_t *protocol, 195*0efe1bcfSAlexander Graf void **protocol_interface, void *agent_handle, 196*0efe1bcfSAlexander Graf void *controller_handle, uint32_t attributes) 197*0efe1bcfSAlexander Graf { 198*0efe1bcfSAlexander Graf struct efi_simple_network *net = handle; 199*0efe1bcfSAlexander Graf struct efi_net_obj *netobj = container_of(net, struct efi_net_obj, net); 200*0efe1bcfSAlexander Graf 201*0efe1bcfSAlexander Graf *protocol_interface = netobj->dp; 202*0efe1bcfSAlexander Graf 203*0efe1bcfSAlexander Graf return EFI_SUCCESS; 204*0efe1bcfSAlexander Graf } 205*0efe1bcfSAlexander Graf 206*0efe1bcfSAlexander Graf static efi_status_t efi_net_open_pxe(void *handle, efi_guid_t *protocol, 207*0efe1bcfSAlexander Graf void **protocol_interface, void *agent_handle, 208*0efe1bcfSAlexander Graf void *controller_handle, uint32_t attributes) 209*0efe1bcfSAlexander Graf { 210*0efe1bcfSAlexander Graf struct efi_simple_network *net = handle; 211*0efe1bcfSAlexander Graf struct efi_net_obj *netobj = container_of(net, struct efi_net_obj, net); 212*0efe1bcfSAlexander Graf 213*0efe1bcfSAlexander Graf *protocol_interface = &netobj->pxe; 214*0efe1bcfSAlexander Graf 215*0efe1bcfSAlexander Graf return EFI_SUCCESS; 216*0efe1bcfSAlexander Graf } 217*0efe1bcfSAlexander Graf 218*0efe1bcfSAlexander Graf void efi_net_set_dhcp_ack(void *pkt, int len) 219*0efe1bcfSAlexander Graf { 220*0efe1bcfSAlexander Graf int maxsize = sizeof(*dhcp_ack); 221*0efe1bcfSAlexander Graf 222*0efe1bcfSAlexander Graf if (!dhcp_ack) 223*0efe1bcfSAlexander Graf dhcp_ack = malloc(maxsize); 224*0efe1bcfSAlexander Graf 225*0efe1bcfSAlexander Graf memcpy(dhcp_ack, pkt, min(len, maxsize)); 226*0efe1bcfSAlexander Graf } 227*0efe1bcfSAlexander Graf 228*0efe1bcfSAlexander Graf /* This gets called from do_bootefi_exec(). */ 229*0efe1bcfSAlexander Graf int efi_net_register(void **handle) 230*0efe1bcfSAlexander Graf { 231*0efe1bcfSAlexander Graf struct efi_net_obj *netobj; 232*0efe1bcfSAlexander Graf struct efi_device_path_file_path dp_net = { 233*0efe1bcfSAlexander Graf .dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE, 234*0efe1bcfSAlexander Graf .dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH, 235*0efe1bcfSAlexander Graf .dp.length = sizeof(dp_net), 236*0efe1bcfSAlexander Graf .str = { 'N', 'e', 't' }, 237*0efe1bcfSAlexander Graf }; 238*0efe1bcfSAlexander Graf struct efi_device_path_file_path dp_end = { 239*0efe1bcfSAlexander Graf .dp.type = DEVICE_PATH_TYPE_END, 240*0efe1bcfSAlexander Graf .dp.sub_type = DEVICE_PATH_SUB_TYPE_END, 241*0efe1bcfSAlexander Graf .dp.length = sizeof(dp_end), 242*0efe1bcfSAlexander Graf }; 243*0efe1bcfSAlexander Graf 244*0efe1bcfSAlexander Graf if (!eth_get_dev()) { 245*0efe1bcfSAlexander Graf /* No eth device active, don't expose any */ 246*0efe1bcfSAlexander Graf return 0; 247*0efe1bcfSAlexander Graf } 248*0efe1bcfSAlexander Graf 249*0efe1bcfSAlexander Graf /* We only expose the "active" eth device, so one is enough */ 250*0efe1bcfSAlexander Graf netobj = calloc(1, sizeof(*netobj)); 251*0efe1bcfSAlexander Graf 252*0efe1bcfSAlexander Graf /* Fill in object data */ 253*0efe1bcfSAlexander Graf netobj->parent.protocols[0].guid = &efi_net_guid; 254*0efe1bcfSAlexander Graf netobj->parent.protocols[0].open = efi_return_handle; 255*0efe1bcfSAlexander Graf netobj->parent.protocols[1].guid = &efi_guid_device_path; 256*0efe1bcfSAlexander Graf netobj->parent.protocols[1].open = efi_net_open_dp; 257*0efe1bcfSAlexander Graf netobj->parent.protocols[2].guid = &efi_pxe_guid; 258*0efe1bcfSAlexander Graf netobj->parent.protocols[2].open = efi_net_open_pxe; 259*0efe1bcfSAlexander Graf netobj->parent.handle = &netobj->net; 260*0efe1bcfSAlexander Graf netobj->net.start = efi_net_start; 261*0efe1bcfSAlexander Graf netobj->net.stop = efi_net_stop; 262*0efe1bcfSAlexander Graf netobj->net.initialize = efi_net_initialize; 263*0efe1bcfSAlexander Graf netobj->net.reset = efi_net_reset; 264*0efe1bcfSAlexander Graf netobj->net.shutdown = efi_net_shutdown; 265*0efe1bcfSAlexander Graf netobj->net.receive_filters = efi_net_receive_filters; 266*0efe1bcfSAlexander Graf netobj->net.station_address = efi_net_station_address; 267*0efe1bcfSAlexander Graf netobj->net.statistics = efi_net_statistics; 268*0efe1bcfSAlexander Graf netobj->net.mcastiptomac = efi_net_mcastiptomac; 269*0efe1bcfSAlexander Graf netobj->net.nvdata = efi_net_nvdata; 270*0efe1bcfSAlexander Graf netobj->net.get_status = efi_net_get_status; 271*0efe1bcfSAlexander Graf netobj->net.transmit = efi_net_transmit; 272*0efe1bcfSAlexander Graf netobj->net.receive = efi_net_receive; 273*0efe1bcfSAlexander Graf netobj->net.mode = &netobj->net_mode; 274*0efe1bcfSAlexander Graf netobj->net_mode.state = EFI_NETWORK_STARTED; 275*0efe1bcfSAlexander Graf netobj->dp[0] = dp_net; 276*0efe1bcfSAlexander Graf netobj->dp[1] = dp_end; 277*0efe1bcfSAlexander Graf memcpy(netobj->net_mode.current_address.mac_addr, eth_get_ethaddr(), 6); 278*0efe1bcfSAlexander Graf netobj->net_mode.max_packet_size = PKTSIZE; 279*0efe1bcfSAlexander Graf 280*0efe1bcfSAlexander Graf netobj->pxe.mode = &netobj->pxe_mode; 281*0efe1bcfSAlexander Graf if (dhcp_ack) 282*0efe1bcfSAlexander Graf netobj->pxe_mode.dhcp_ack = *dhcp_ack; 283*0efe1bcfSAlexander Graf 284*0efe1bcfSAlexander Graf /* Hook net up to the device list */ 285*0efe1bcfSAlexander Graf list_add_tail(&netobj->parent.link, &efi_obj_list); 286*0efe1bcfSAlexander Graf 287*0efe1bcfSAlexander Graf if (handle) 288*0efe1bcfSAlexander Graf *handle = &netobj->net; 289*0efe1bcfSAlexander Graf 290*0efe1bcfSAlexander Graf return 0; 291*0efe1bcfSAlexander Graf } 292