183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
25ca23ed5SHeinrich Schuchardt /*
35ca23ed5SHeinrich Schuchardt * efi_selftest_snp
45ca23ed5SHeinrich Schuchardt *
55ca23ed5SHeinrich Schuchardt * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de>
65ca23ed5SHeinrich Schuchardt *
75ca23ed5SHeinrich Schuchardt * This unit test covers the Simple Network Protocol as well as
85ca23ed5SHeinrich Schuchardt * the CopyMem and SetMem boottime services.
95ca23ed5SHeinrich Schuchardt *
105ca23ed5SHeinrich Schuchardt * A DHCP discover message is sent. The test is successful if a
115ca23ed5SHeinrich Schuchardt * DHCP reply is received.
125ca23ed5SHeinrich Schuchardt *
135ca23ed5SHeinrich Schuchardt * TODO: Once ConnectController and DisconnectController are implemented
145ca23ed5SHeinrich Schuchardt * we should connect our code as controller.
155ca23ed5SHeinrich Schuchardt */
165ca23ed5SHeinrich Schuchardt
175ca23ed5SHeinrich Schuchardt #include <efi_selftest.h>
185ca23ed5SHeinrich Schuchardt
195ca23ed5SHeinrich Schuchardt /*
205ca23ed5SHeinrich Schuchardt * MAC address for broadcasts
215ca23ed5SHeinrich Schuchardt */
225ca23ed5SHeinrich Schuchardt static const u8 BROADCAST_MAC[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
235ca23ed5SHeinrich Schuchardt
245ca23ed5SHeinrich Schuchardt struct dhcp_hdr {
255ca23ed5SHeinrich Schuchardt u8 op;
265ca23ed5SHeinrich Schuchardt #define BOOTREQUEST 1
275ca23ed5SHeinrich Schuchardt #define BOOTREPLY 2
285ca23ed5SHeinrich Schuchardt u8 htype;
295ca23ed5SHeinrich Schuchardt # define HWT_ETHER 1
305ca23ed5SHeinrich Schuchardt u8 hlen;
315ca23ed5SHeinrich Schuchardt # define HWL_ETHER 6
325ca23ed5SHeinrich Schuchardt u8 hops;
335ca23ed5SHeinrich Schuchardt u32 xid;
345ca23ed5SHeinrich Schuchardt u16 secs;
355ca23ed5SHeinrich Schuchardt u16 flags;
365ca23ed5SHeinrich Schuchardt #define DHCP_FLAGS_UNICAST 0x0000
375ca23ed5SHeinrich Schuchardt #define DHCP_FLAGS_BROADCAST 0x0080
385ca23ed5SHeinrich Schuchardt u32 ciaddr;
395ca23ed5SHeinrich Schuchardt u32 yiaddr;
405ca23ed5SHeinrich Schuchardt u32 siaddr;
415ca23ed5SHeinrich Schuchardt u32 giaddr;
425ca23ed5SHeinrich Schuchardt u8 chaddr[16];
435ca23ed5SHeinrich Schuchardt u8 sname[64];
445ca23ed5SHeinrich Schuchardt u8 file[128];
455ca23ed5SHeinrich Schuchardt };
465ca23ed5SHeinrich Schuchardt
475ca23ed5SHeinrich Schuchardt /*
485ca23ed5SHeinrich Schuchardt * Message type option.
495ca23ed5SHeinrich Schuchardt */
505ca23ed5SHeinrich Schuchardt #define DHCP_MESSAGE_TYPE 0x35
515ca23ed5SHeinrich Schuchardt #define DHCPDISCOVER 1
525ca23ed5SHeinrich Schuchardt #define DHCPOFFER 2
535ca23ed5SHeinrich Schuchardt #define DHCPREQUEST 3
545ca23ed5SHeinrich Schuchardt #define DHCPDECLINE 4
555ca23ed5SHeinrich Schuchardt #define DHCPACK 5
565ca23ed5SHeinrich Schuchardt #define DHCPNAK 6
575ca23ed5SHeinrich Schuchardt #define DHCPRELEASE 7
585ca23ed5SHeinrich Schuchardt
595ca23ed5SHeinrich Schuchardt struct dhcp {
605ca23ed5SHeinrich Schuchardt struct ethernet_hdr eth_hdr;
615ca23ed5SHeinrich Schuchardt struct ip_udp_hdr ip_udp;
625ca23ed5SHeinrich Schuchardt struct dhcp_hdr dhcp_hdr;
635ca23ed5SHeinrich Schuchardt u8 opt[128];
645ca23ed5SHeinrich Schuchardt } __packed;
655ca23ed5SHeinrich Schuchardt
665ca23ed5SHeinrich Schuchardt static struct efi_boot_services *boottime;
675ca23ed5SHeinrich Schuchardt static struct efi_simple_network *net;
685ca23ed5SHeinrich Schuchardt static struct efi_event *timer;
695ca23ed5SHeinrich Schuchardt static const efi_guid_t efi_net_guid = EFI_SIMPLE_NETWORK_GUID;
705ca23ed5SHeinrich Schuchardt /* IP packet ID */
715ca23ed5SHeinrich Schuchardt static unsigned int net_ip_id;
725ca23ed5SHeinrich Schuchardt
735ca23ed5SHeinrich Schuchardt /*
745ca23ed5SHeinrich Schuchardt * Compute the checksum of the IP header. We cover even values of length only.
755ca23ed5SHeinrich Schuchardt * We cannot use net/checksum.c due to different CFLAGS values.
765ca23ed5SHeinrich Schuchardt *
775ca23ed5SHeinrich Schuchardt * @buf: IP header
785ca23ed5SHeinrich Schuchardt * @len: length of header in bytes
795ca23ed5SHeinrich Schuchardt * @return: checksum
805ca23ed5SHeinrich Schuchardt */
efi_ip_checksum(const void * buf,size_t len)815ca23ed5SHeinrich Schuchardt static unsigned int efi_ip_checksum(const void *buf, size_t len)
825ca23ed5SHeinrich Schuchardt {
835ca23ed5SHeinrich Schuchardt size_t i;
845ca23ed5SHeinrich Schuchardt u32 sum = 0;
855ca23ed5SHeinrich Schuchardt const u16 *pos = buf;
865ca23ed5SHeinrich Schuchardt
875ca23ed5SHeinrich Schuchardt for (i = 0; i < len; i += 2)
885ca23ed5SHeinrich Schuchardt sum += *pos++;
895ca23ed5SHeinrich Schuchardt
905ca23ed5SHeinrich Schuchardt sum = (sum >> 16) + (sum & 0xffff);
915ca23ed5SHeinrich Schuchardt sum += sum >> 16;
925ca23ed5SHeinrich Schuchardt sum = ~sum & 0xffff;
935ca23ed5SHeinrich Schuchardt
945ca23ed5SHeinrich Schuchardt return sum;
955ca23ed5SHeinrich Schuchardt }
965ca23ed5SHeinrich Schuchardt
975ca23ed5SHeinrich Schuchardt /*
985ca23ed5SHeinrich Schuchardt * Transmit a DHCPDISCOVER message.
995ca23ed5SHeinrich Schuchardt */
send_dhcp_discover(void)1005ca23ed5SHeinrich Schuchardt static efi_status_t send_dhcp_discover(void)
1015ca23ed5SHeinrich Schuchardt {
1025ca23ed5SHeinrich Schuchardt efi_status_t ret;
1035ca23ed5SHeinrich Schuchardt struct dhcp p = {};
1045ca23ed5SHeinrich Schuchardt
1055ca23ed5SHeinrich Schuchardt /*
1060fdb9e30SHeinrich Schuchardt * Fill Ethernet header
1075ca23ed5SHeinrich Schuchardt */
1085ca23ed5SHeinrich Schuchardt boottime->copy_mem(p.eth_hdr.et_dest, (void *)BROADCAST_MAC, ARP_HLEN);
1095ca23ed5SHeinrich Schuchardt boottime->copy_mem(p.eth_hdr.et_src, &net->mode->current_address,
1105ca23ed5SHeinrich Schuchardt ARP_HLEN);
1115ca23ed5SHeinrich Schuchardt p.eth_hdr.et_protlen = htons(PROT_IP);
1125ca23ed5SHeinrich Schuchardt /*
1135ca23ed5SHeinrich Schuchardt * Fill IP header
1145ca23ed5SHeinrich Schuchardt */
1155ca23ed5SHeinrich Schuchardt p.ip_udp.ip_hl_v = 0x45;
1165ca23ed5SHeinrich Schuchardt p.ip_udp.ip_len = htons(sizeof(struct dhcp) -
1175ca23ed5SHeinrich Schuchardt sizeof(struct ethernet_hdr));
1185ca23ed5SHeinrich Schuchardt p.ip_udp.ip_id = htons(++net_ip_id);
1195ca23ed5SHeinrich Schuchardt p.ip_udp.ip_off = htons(IP_FLAGS_DFRAG);
1205ca23ed5SHeinrich Schuchardt p.ip_udp.ip_ttl = 0xff; /* time to live */
1215ca23ed5SHeinrich Schuchardt p.ip_udp.ip_p = IPPROTO_UDP;
1225ca23ed5SHeinrich Schuchardt boottime->set_mem(&p.ip_udp.ip_dst, 4, 0xff);
1235ca23ed5SHeinrich Schuchardt p.ip_udp.ip_sum = efi_ip_checksum(&p.ip_udp, IP_HDR_SIZE);
1245ca23ed5SHeinrich Schuchardt
1255ca23ed5SHeinrich Schuchardt /*
1265ca23ed5SHeinrich Schuchardt * Fill UDP header
1275ca23ed5SHeinrich Schuchardt */
1285ca23ed5SHeinrich Schuchardt p.ip_udp.udp_src = htons(68);
1295ca23ed5SHeinrich Schuchardt p.ip_udp.udp_dst = htons(67);
1305ca23ed5SHeinrich Schuchardt p.ip_udp.udp_len = htons(sizeof(struct dhcp) -
1315ca23ed5SHeinrich Schuchardt sizeof(struct ethernet_hdr) -
1325ca23ed5SHeinrich Schuchardt sizeof(struct ip_hdr));
1335ca23ed5SHeinrich Schuchardt /*
1345ca23ed5SHeinrich Schuchardt * Fill DHCP header
1355ca23ed5SHeinrich Schuchardt */
1365ca23ed5SHeinrich Schuchardt p.dhcp_hdr.op = BOOTREQUEST;
1375ca23ed5SHeinrich Schuchardt p.dhcp_hdr.htype = HWT_ETHER;
1385ca23ed5SHeinrich Schuchardt p.dhcp_hdr.hlen = HWL_ETHER;
1395ca23ed5SHeinrich Schuchardt p.dhcp_hdr.flags = htons(DHCP_FLAGS_UNICAST);
1405ca23ed5SHeinrich Schuchardt boottime->copy_mem(&p.dhcp_hdr.chaddr,
1415ca23ed5SHeinrich Schuchardt &net->mode->current_address, ARP_HLEN);
1425ca23ed5SHeinrich Schuchardt /*
1435ca23ed5SHeinrich Schuchardt * Fill options
1445ca23ed5SHeinrich Schuchardt */
1455ca23ed5SHeinrich Schuchardt p.opt[0] = 0x63; /* DHCP magic cookie */
1465ca23ed5SHeinrich Schuchardt p.opt[1] = 0x82;
1475ca23ed5SHeinrich Schuchardt p.opt[2] = 0x53;
1485ca23ed5SHeinrich Schuchardt p.opt[3] = 0x63;
1495ca23ed5SHeinrich Schuchardt p.opt[4] = DHCP_MESSAGE_TYPE;
1505ca23ed5SHeinrich Schuchardt p.opt[5] = 0x01; /* length */
1515ca23ed5SHeinrich Schuchardt p.opt[6] = DHCPDISCOVER;
1525ca23ed5SHeinrich Schuchardt p.opt[7] = 0x39; /* maximum message size */
1535ca23ed5SHeinrich Schuchardt p.opt[8] = 0x02; /* length */
1545ca23ed5SHeinrich Schuchardt p.opt[9] = 0x02; /* 576 bytes */
1555ca23ed5SHeinrich Schuchardt p.opt[10] = 0x40;
1565ca23ed5SHeinrich Schuchardt p.opt[11] = 0xff; /* end of options */
1575ca23ed5SHeinrich Schuchardt
1585ca23ed5SHeinrich Schuchardt /*
1595ca23ed5SHeinrich Schuchardt * Transmit DHCPDISCOVER message.
1605ca23ed5SHeinrich Schuchardt */
1615ca23ed5SHeinrich Schuchardt ret = net->transmit(net, 0, sizeof(struct dhcp), &p, NULL, NULL, 0);
1625ca23ed5SHeinrich Schuchardt if (ret != EFI_SUCCESS)
1635ca23ed5SHeinrich Schuchardt efi_st_error("Sending a DHCP request failed\n");
1645ca23ed5SHeinrich Schuchardt else
1655ca23ed5SHeinrich Schuchardt efi_st_printf("DHCP Discover\n");
1665ca23ed5SHeinrich Schuchardt return ret;
1675ca23ed5SHeinrich Schuchardt }
1685ca23ed5SHeinrich Schuchardt
1695ca23ed5SHeinrich Schuchardt /*
1705ca23ed5SHeinrich Schuchardt * Setup unit test.
1715ca23ed5SHeinrich Schuchardt *
1725ca23ed5SHeinrich Schuchardt * Create a 1 s periodic timer.
1735ca23ed5SHeinrich Schuchardt * Start the network driver.
1745ca23ed5SHeinrich Schuchardt *
1755ca23ed5SHeinrich Schuchardt * @handle: handle of the loaded image
1765ca23ed5SHeinrich Schuchardt * @systable: system table
1775ca23ed5SHeinrich Schuchardt * @return: EFI_ST_SUCCESS for success
1785ca23ed5SHeinrich Schuchardt */
setup(const efi_handle_t handle,const struct efi_system_table * systable)1795ca23ed5SHeinrich Schuchardt static int setup(const efi_handle_t handle,
1805ca23ed5SHeinrich Schuchardt const struct efi_system_table *systable)
1815ca23ed5SHeinrich Schuchardt {
1825ca23ed5SHeinrich Schuchardt efi_status_t ret;
1835ca23ed5SHeinrich Schuchardt
1845ca23ed5SHeinrich Schuchardt boottime = systable->boottime;
1855ca23ed5SHeinrich Schuchardt
1865ca23ed5SHeinrich Schuchardt /*
1875ca23ed5SHeinrich Schuchardt * Create a timer event.
1885ca23ed5SHeinrich Schuchardt */
1895ca23ed5SHeinrich Schuchardt ret = boottime->create_event(EVT_TIMER, TPL_CALLBACK, NULL, NULL,
1905ca23ed5SHeinrich Schuchardt &timer);
1915ca23ed5SHeinrich Schuchardt if (ret != EFI_SUCCESS) {
1925ca23ed5SHeinrich Schuchardt efi_st_error("Failed to create event\n");
1935ca23ed5SHeinrich Schuchardt return EFI_ST_FAILURE;
1945ca23ed5SHeinrich Schuchardt }
1955ca23ed5SHeinrich Schuchardt /*
1965ca23ed5SHeinrich Schuchardt * Set timer period to 1s.
1975ca23ed5SHeinrich Schuchardt */
1985ca23ed5SHeinrich Schuchardt ret = boottime->set_timer(timer, EFI_TIMER_PERIODIC, 10000000);
1995ca23ed5SHeinrich Schuchardt if (ret != EFI_SUCCESS) {
200fdd04563SHeinrich Schuchardt efi_st_error("Failed to set timer\n");
2015ca23ed5SHeinrich Schuchardt return EFI_ST_FAILURE;
2025ca23ed5SHeinrich Schuchardt }
2035ca23ed5SHeinrich Schuchardt /*
2045ca23ed5SHeinrich Schuchardt * Find an interface implementing the SNP protocol.
2055ca23ed5SHeinrich Schuchardt */
2065ca23ed5SHeinrich Schuchardt ret = boottime->locate_protocol(&efi_net_guid, NULL, (void **)&net);
2075ca23ed5SHeinrich Schuchardt if (ret != EFI_SUCCESS) {
208fdd04563SHeinrich Schuchardt net = NULL;
2095ca23ed5SHeinrich Schuchardt efi_st_error("Failed to locate simple network protocol\n");
2105ca23ed5SHeinrich Schuchardt return EFI_ST_FAILURE;
2115ca23ed5SHeinrich Schuchardt }
2125ca23ed5SHeinrich Schuchardt /*
2135ca23ed5SHeinrich Schuchardt * Check hardware address size.
2145ca23ed5SHeinrich Schuchardt */
2155ca23ed5SHeinrich Schuchardt if (!net->mode) {
2165ca23ed5SHeinrich Schuchardt efi_st_error("Mode not provided\n");
2175ca23ed5SHeinrich Schuchardt return EFI_ST_FAILURE;
2185ca23ed5SHeinrich Schuchardt }
2195ca23ed5SHeinrich Schuchardt if (net->mode->hwaddr_size != ARP_HLEN) {
2205ca23ed5SHeinrich Schuchardt efi_st_error("HwAddressSize = %u, expected %u\n",
2215ca23ed5SHeinrich Schuchardt net->mode->hwaddr_size, ARP_HLEN);
2225ca23ed5SHeinrich Schuchardt return EFI_ST_FAILURE;
2235ca23ed5SHeinrich Schuchardt }
2245ca23ed5SHeinrich Schuchardt /*
2255ca23ed5SHeinrich Schuchardt * Check that WaitForPacket event exists.
2265ca23ed5SHeinrich Schuchardt */
2275ca23ed5SHeinrich Schuchardt if (!net->wait_for_packet) {
2285ca23ed5SHeinrich Schuchardt efi_st_error("WaitForPacket event missing\n");
2295ca23ed5SHeinrich Schuchardt return EFI_ST_FAILURE;
2305ca23ed5SHeinrich Schuchardt }
2315ca23ed5SHeinrich Schuchardt /*
2320fdb9e30SHeinrich Schuchardt * Start network adapter.
2330fdb9e30SHeinrich Schuchardt */
2340fdb9e30SHeinrich Schuchardt ret = net->start(net);
2350fdb9e30SHeinrich Schuchardt if (ret != EFI_SUCCESS && ret != EFI_ALREADY_STARTED) {
2360fdb9e30SHeinrich Schuchardt efi_st_error("Failed to start network adapter\n");
2370fdb9e30SHeinrich Schuchardt return EFI_ST_FAILURE;
2380fdb9e30SHeinrich Schuchardt }
2390fdb9e30SHeinrich Schuchardt /*
2405ca23ed5SHeinrich Schuchardt * Initialize network adapter.
2415ca23ed5SHeinrich Schuchardt */
2425ca23ed5SHeinrich Schuchardt ret = net->initialize(net, 0, 0);
2435ca23ed5SHeinrich Schuchardt if (ret != EFI_SUCCESS) {
2445ca23ed5SHeinrich Schuchardt efi_st_error("Failed to initialize network adapter\n");
2455ca23ed5SHeinrich Schuchardt return EFI_ST_FAILURE;
2465ca23ed5SHeinrich Schuchardt }
2475ca23ed5SHeinrich Schuchardt return EFI_ST_SUCCESS;
2485ca23ed5SHeinrich Schuchardt }
2495ca23ed5SHeinrich Schuchardt
2505ca23ed5SHeinrich Schuchardt /*
2515ca23ed5SHeinrich Schuchardt * Execute unit test.
2525ca23ed5SHeinrich Schuchardt *
2535ca23ed5SHeinrich Schuchardt * A DHCP discover message is sent. The test is successful if a
2545ca23ed5SHeinrich Schuchardt * DHCP reply is received within 10 seconds.
2555ca23ed5SHeinrich Schuchardt *
2565ca23ed5SHeinrich Schuchardt * @return: EFI_ST_SUCCESS for success
2575ca23ed5SHeinrich Schuchardt */
execute(void)2585ca23ed5SHeinrich Schuchardt static int execute(void)
2595ca23ed5SHeinrich Schuchardt {
2605ca23ed5SHeinrich Schuchardt efi_status_t ret;
2615ca23ed5SHeinrich Schuchardt struct efi_event *events[2];
262f5a2a938SHeinrich Schuchardt efi_uintn_t index;
2635ca23ed5SHeinrich Schuchardt union {
2645ca23ed5SHeinrich Schuchardt struct dhcp p;
2655ca23ed5SHeinrich Schuchardt u8 b[PKTSIZE];
2665ca23ed5SHeinrich Schuchardt } buffer;
2675ca23ed5SHeinrich Schuchardt struct efi_mac_address srcaddr;
2685ca23ed5SHeinrich Schuchardt struct efi_mac_address destaddr;
2695ca23ed5SHeinrich Schuchardt size_t buffer_size;
2705ca23ed5SHeinrich Schuchardt u8 *addr;
2715ca23ed5SHeinrich Schuchardt /*
2725ca23ed5SHeinrich Schuchardt * The timeout is to occur after 10 s.
2735ca23ed5SHeinrich Schuchardt */
2745ca23ed5SHeinrich Schuchardt unsigned int timeout = 10;
2755ca23ed5SHeinrich Schuchardt
276fdd04563SHeinrich Schuchardt /* Setup may have failed */
277fdd04563SHeinrich Schuchardt if (!net || !timer) {
278fdd04563SHeinrich Schuchardt efi_st_error("Cannot execute test after setup failure\n");
279fdd04563SHeinrich Schuchardt return EFI_ST_FAILURE;
280fdd04563SHeinrich Schuchardt }
281fdd04563SHeinrich Schuchardt
2825ca23ed5SHeinrich Schuchardt /*
2835ca23ed5SHeinrich Schuchardt * Send DHCP discover message
2845ca23ed5SHeinrich Schuchardt */
2855ca23ed5SHeinrich Schuchardt ret = send_dhcp_discover();
2865ca23ed5SHeinrich Schuchardt if (ret != EFI_SUCCESS)
2875ca23ed5SHeinrich Schuchardt return EFI_ST_FAILURE;
2885ca23ed5SHeinrich Schuchardt
2895ca23ed5SHeinrich Schuchardt /*
2905ca23ed5SHeinrich Schuchardt * If we would call WaitForEvent only with the WaitForPacket event,
2915ca23ed5SHeinrich Schuchardt * our code would block until a packet is received which might never
2925ca23ed5SHeinrich Schuchardt * occur. By calling WaitFor event with both a timer event and the
2935ca23ed5SHeinrich Schuchardt * WaitForPacket event we can escape this blocking situation.
2945ca23ed5SHeinrich Schuchardt *
2955ca23ed5SHeinrich Schuchardt * If the timer event occurs before we have received a DHCP reply
2965ca23ed5SHeinrich Schuchardt * a further DHCP discover message is sent.
2975ca23ed5SHeinrich Schuchardt */
2985ca23ed5SHeinrich Schuchardt events[0] = timer;
2995ca23ed5SHeinrich Schuchardt events[1] = net->wait_for_packet;
3005ca23ed5SHeinrich Schuchardt for (;;) {
3015ca23ed5SHeinrich Schuchardt /*
3025ca23ed5SHeinrich Schuchardt * Wait for packet to be received or timer event.
3035ca23ed5SHeinrich Schuchardt */
3045ca23ed5SHeinrich Schuchardt boottime->wait_for_event(2, events, &index);
3055ca23ed5SHeinrich Schuchardt if (index == 0) {
3065ca23ed5SHeinrich Schuchardt /*
3075ca23ed5SHeinrich Schuchardt * The timer event occurred. Check for timeout.
3085ca23ed5SHeinrich Schuchardt */
3095ca23ed5SHeinrich Schuchardt --timeout;
3105ca23ed5SHeinrich Schuchardt if (!timeout) {
3115ca23ed5SHeinrich Schuchardt efi_st_error("Timeout occurred\n");
3125ca23ed5SHeinrich Schuchardt return EFI_ST_FAILURE;
3135ca23ed5SHeinrich Schuchardt }
3145ca23ed5SHeinrich Schuchardt /*
3155ca23ed5SHeinrich Schuchardt * Send further DHCP discover message
3165ca23ed5SHeinrich Schuchardt */
3175ca23ed5SHeinrich Schuchardt ret = send_dhcp_discover();
3185ca23ed5SHeinrich Schuchardt if (ret != EFI_SUCCESS)
3195ca23ed5SHeinrich Schuchardt return EFI_ST_FAILURE;
3205ca23ed5SHeinrich Schuchardt continue;
3215ca23ed5SHeinrich Schuchardt }
3225ca23ed5SHeinrich Schuchardt /*
3235ca23ed5SHeinrich Schuchardt * Receive packet
3245ca23ed5SHeinrich Schuchardt */
3255ca23ed5SHeinrich Schuchardt buffer_size = sizeof(buffer);
3265ca23ed5SHeinrich Schuchardt net->receive(net, NULL, &buffer_size, &buffer,
3275ca23ed5SHeinrich Schuchardt &srcaddr, &destaddr, NULL);
3285ca23ed5SHeinrich Schuchardt if (ret != EFI_SUCCESS) {
3295ca23ed5SHeinrich Schuchardt efi_st_error("Failed to receive packet");
3305ca23ed5SHeinrich Schuchardt return EFI_ST_FAILURE;
3315ca23ed5SHeinrich Schuchardt }
3325ca23ed5SHeinrich Schuchardt /*
3335ca23ed5SHeinrich Schuchardt * Check the packet is meant for this system.
3345ca23ed5SHeinrich Schuchardt * Unfortunately QEMU ignores the broadcast flag.
3355ca23ed5SHeinrich Schuchardt * So we have to check for broadcasts too.
3365ca23ed5SHeinrich Schuchardt */
3375ca23ed5SHeinrich Schuchardt if (efi_st_memcmp(&destaddr, &net->mode->current_address,
3385ca23ed5SHeinrich Schuchardt ARP_HLEN) &&
3395ca23ed5SHeinrich Schuchardt efi_st_memcmp(&destaddr, BROADCAST_MAC, ARP_HLEN))
3405ca23ed5SHeinrich Schuchardt continue;
3415ca23ed5SHeinrich Schuchardt /*
3425ca23ed5SHeinrich Schuchardt * Check this is a DHCP reply
3435ca23ed5SHeinrich Schuchardt */
3445ca23ed5SHeinrich Schuchardt if (buffer.p.eth_hdr.et_protlen != ntohs(PROT_IP) ||
3455ca23ed5SHeinrich Schuchardt buffer.p.ip_udp.ip_hl_v != 0x45 ||
3465ca23ed5SHeinrich Schuchardt buffer.p.ip_udp.ip_p != IPPROTO_UDP ||
3475ca23ed5SHeinrich Schuchardt buffer.p.ip_udp.udp_src != ntohs(67) ||
3485ca23ed5SHeinrich Schuchardt buffer.p.ip_udp.udp_dst != ntohs(68) ||
3495ca23ed5SHeinrich Schuchardt buffer.p.dhcp_hdr.op != BOOTREPLY)
3505ca23ed5SHeinrich Schuchardt continue;
3515ca23ed5SHeinrich Schuchardt /*
3525ca23ed5SHeinrich Schuchardt * We successfully received a DHCP reply.
3535ca23ed5SHeinrich Schuchardt */
3545ca23ed5SHeinrich Schuchardt break;
3555ca23ed5SHeinrich Schuchardt }
3565ca23ed5SHeinrich Schuchardt
3575ca23ed5SHeinrich Schuchardt /*
3585ca23ed5SHeinrich Schuchardt * Write a log message.
3595ca23ed5SHeinrich Schuchardt */
3605ca23ed5SHeinrich Schuchardt addr = (u8 *)&buffer.p.ip_udp.ip_src;
3615ca23ed5SHeinrich Schuchardt efi_st_printf("DHCP reply received from %u.%u.%u.%u (%pm) ",
3625ca23ed5SHeinrich Schuchardt addr[0], addr[1], addr[2], addr[3], &srcaddr);
3635ca23ed5SHeinrich Schuchardt if (!efi_st_memcmp(&destaddr, BROADCAST_MAC, ARP_HLEN))
3645ca23ed5SHeinrich Schuchardt efi_st_printf("as broadcast message.\n");
3655ca23ed5SHeinrich Schuchardt else
3665ca23ed5SHeinrich Schuchardt efi_st_printf("as unicast message.\n");
3675ca23ed5SHeinrich Schuchardt
3685ca23ed5SHeinrich Schuchardt return EFI_ST_SUCCESS;
3695ca23ed5SHeinrich Schuchardt }
3705ca23ed5SHeinrich Schuchardt
3715ca23ed5SHeinrich Schuchardt /*
3725ca23ed5SHeinrich Schuchardt * Tear down unit test.
3735ca23ed5SHeinrich Schuchardt *
3745ca23ed5SHeinrich Schuchardt * Close the timer event created in setup.
3755ca23ed5SHeinrich Schuchardt * Shut down the network adapter.
3765ca23ed5SHeinrich Schuchardt *
3775ca23ed5SHeinrich Schuchardt * @return: EFI_ST_SUCCESS for success
3785ca23ed5SHeinrich Schuchardt */
teardown(void)3795ca23ed5SHeinrich Schuchardt static int teardown(void)
3805ca23ed5SHeinrich Schuchardt {
3815ca23ed5SHeinrich Schuchardt efi_status_t ret;
3825ca23ed5SHeinrich Schuchardt int exit_status = EFI_ST_SUCCESS;
3835ca23ed5SHeinrich Schuchardt
3845ca23ed5SHeinrich Schuchardt if (timer) {
3855ca23ed5SHeinrich Schuchardt /*
3865ca23ed5SHeinrich Schuchardt * Stop timer.
3875ca23ed5SHeinrich Schuchardt */
3885ca23ed5SHeinrich Schuchardt ret = boottime->set_timer(timer, EFI_TIMER_STOP, 0);
3895ca23ed5SHeinrich Schuchardt if (ret != EFI_SUCCESS) {
3905ca23ed5SHeinrich Schuchardt efi_st_error("Failed to stop timer");
3915ca23ed5SHeinrich Schuchardt exit_status = EFI_ST_FAILURE;
3925ca23ed5SHeinrich Schuchardt }
3935ca23ed5SHeinrich Schuchardt /*
3945ca23ed5SHeinrich Schuchardt * Close timer event.
3955ca23ed5SHeinrich Schuchardt */
3965ca23ed5SHeinrich Schuchardt ret = boottime->close_event(timer);
3975ca23ed5SHeinrich Schuchardt if (ret != EFI_SUCCESS) {
3985ca23ed5SHeinrich Schuchardt efi_st_error("Failed to close event");
3995ca23ed5SHeinrich Schuchardt exit_status = EFI_ST_FAILURE;
4005ca23ed5SHeinrich Schuchardt }
4015ca23ed5SHeinrich Schuchardt }
4025ca23ed5SHeinrich Schuchardt if (net) {
4035ca23ed5SHeinrich Schuchardt /*
4045ca23ed5SHeinrich Schuchardt * Stop network adapter.
4055ca23ed5SHeinrich Schuchardt */
4065ca23ed5SHeinrich Schuchardt ret = net->stop(net);
4075ca23ed5SHeinrich Schuchardt if (ret != EFI_SUCCESS) {
4085ca23ed5SHeinrich Schuchardt efi_st_error("Failed to stop network adapter\n");
4095ca23ed5SHeinrich Schuchardt exit_status = EFI_ST_FAILURE;
4105ca23ed5SHeinrich Schuchardt }
4115ca23ed5SHeinrich Schuchardt /*
4125ca23ed5SHeinrich Schuchardt * Shut down network adapter.
4135ca23ed5SHeinrich Schuchardt */
4145ca23ed5SHeinrich Schuchardt ret = net->shutdown(net);
4155ca23ed5SHeinrich Schuchardt if (ret != EFI_SUCCESS) {
4165ca23ed5SHeinrich Schuchardt efi_st_error("Failed to shut down network adapter\n");
4175ca23ed5SHeinrich Schuchardt exit_status = EFI_ST_FAILURE;
4185ca23ed5SHeinrich Schuchardt }
4195ca23ed5SHeinrich Schuchardt }
4205ca23ed5SHeinrich Schuchardt
4215ca23ed5SHeinrich Schuchardt return exit_status;
4225ca23ed5SHeinrich Schuchardt }
4235ca23ed5SHeinrich Schuchardt
4245ca23ed5SHeinrich Schuchardt EFI_UNIT_TEST(snp) = {
4255ca23ed5SHeinrich Schuchardt .name = "simple network protocol",
4265ca23ed5SHeinrich Schuchardt .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
4275ca23ed5SHeinrich Schuchardt .setup = setup,
4285ca23ed5SHeinrich Schuchardt .execute = execute,
4295ca23ed5SHeinrich Schuchardt .teardown = teardown,
430*8a42641aSHeinrich Schuchardt #ifdef CONFIG_SANDBOX
431*8a42641aSHeinrich Schuchardt /*
432*8a42641aSHeinrich Schuchardt * Running this test on the sandbox requires setting environment
433*8a42641aSHeinrich Schuchardt * variable ethact to a network interface connected to a DHCP server and
434*8a42641aSHeinrich Schuchardt * ethrotate to 'no'.
435*8a42641aSHeinrich Schuchardt */
436*8a42641aSHeinrich Schuchardt .on_request = true,
437*8a42641aSHeinrich Schuchardt #endif
4385ca23ed5SHeinrich Schuchardt };
439