1/*
2 * Copyright 2013-2014 Intel Corporation - All Rights Reserved
3 */
4
5#include <syslinux/firmware.h>
6#include <syslinux/pxe_api.h>
7#include "efi.h"
8#include "net.h"
9#include "fs/pxe/pxe.h"
10
11const struct url_scheme url_schemes[] = {
12    { "tftp", tftp_open, 0 },
13    { "http", http_open, O_DIRECTORY },
14    { "ftp",  ftp_open,  O_DIRECTORY },
15    { NULL, NULL, 0 },
16};
17
18/**
19 * Network stack-specific initialization
20 */
21void net_core_init(void)
22{
23    http_bake_cookies();
24}
25
26void pxe_init_isr(void) {}
27void gpxe_init(void) {}
28void pxe_idle_init(void) {}
29
30int reset_pxe(void)
31{
32    return 0;
33}
34
35#define DNS_MAX_SERVERS 4		/* Max no of DNS servers */
36uint32_t dns_server[DNS_MAX_SERVERS] = {0, };
37
38__export uint32_t dns_resolv(const char *name)
39{
40    /*
41     * Return failure on an empty input... this can happen during
42     * some types of URL parsing, and this is the easiest place to
43     * check for it.
44     */
45    if (!name || !*name)
46	return 0;
47
48    return 0;
49}
50
51int pxe_init(bool quiet)
52{
53    EFI_HANDLE *handles;
54    EFI_STATUS status;
55    UINTN nr_handles;
56
57    status = LibLocateHandle(ByProtocol, &PxeBaseCodeProtocol,
58			     NULL, &nr_handles, &handles);
59    if (status != EFI_SUCCESS) {
60	if (!quiet)
61	    Print(L"No PXE Base Code Protocol\n");
62	return -1;
63    }
64
65    return 0;
66}
67
68#define EDHCP_BUF_LEN 8192
69
70struct embedded_dhcp_options {
71    uint32_t magic[4];
72    uint32_t bdhcp_len;
73    uint32_t adhcp_len;
74    uint32_t buffer_size;
75    uint32_t reserved;
76    uint8_t  dhcp_data[EDHCP_BUF_LEN];
77} __attribute__((aligned(16)));
78
79struct embedded_dhcp_options embedded_dhcp_options =
80{
81    .magic[0] = 0x2a171ead,
82    .magic[1] = 0x0600e65e,
83    .magic[2] = 0x4025a4e4,
84    .magic[3] = 0x42388fc8,
85    .bdhcp_len = 0,
86    .adhcp_len = 0,
87    .buffer_size = EDHCP_BUF_LEN,
88};
89
90void net_parse_dhcp(void)
91{
92    EFI_PXE_BASE_CODE_MODE *mode;
93    EFI_PXE_BASE_CODE *bc;
94    unsigned int pkt_len = sizeof(EFI_PXE_BASE_CODE_PACKET);
95    EFI_STATUS status;
96    EFI_HANDLE *handles = NULL;
97    UINTN nr_handles = 0;
98    uint8_t hardlen;
99    uint32_t ip;
100    char dst[256];
101
102    status = LibLocateHandle(ByProtocol, &PxeBaseCodeProtocol,
103			 NULL, &nr_handles, &handles);
104    if (status != EFI_SUCCESS)
105	return;
106
107    /* Probably want to use IPv4 protocol to decide which handle to use */
108    status = uefi_call_wrapper(BS->HandleProtocol, 3, handles[0],
109			   &PxeBaseCodeProtocol, (void **)&bc);
110    if (status != EFI_SUCCESS) {
111	Print(L"Failed to lookup PxeBaseCodeProtocol\n");
112    }
113
114    mode = bc->Mode;
115
116    /*
117     * Parse any "before" hardcoded options
118     */
119    parse_dhcp_options(embedded_dhcp_options.dhcp_data,
120		       embedded_dhcp_options.bdhcp_len, 0);
121
122    /*
123     * Get the DHCP client identifiers (query info 1)
124     */
125    Print(L"Getting cached packet ");
126    parse_dhcp(&mode->DhcpDiscover.Dhcpv4, pkt_len);
127    /*
128     * We don't use flags from the request packet, so
129     * this is a good time to initialize DHCPMagic...
130     * Initialize it to 1 meaning we will accept options found;
131     * in earlier versions of PXELINUX bit 0 was used to indicate
132     * we have found option 208 with the appropriate magic number;
133     * we no longer require that, but MAY want to re-introduce
134     * it in the future for vendor encapsulated options.
135     */
136    *(char *)&DHCPMagic = 1;
137
138    /*
139     * Get the BOOTP/DHCP packet that brought us file (and an IP
140     * address). This lives in the DHCPACK packet (query info 2)
141     */
142    parse_dhcp(&mode->DhcpAck.Dhcpv4, pkt_len);
143    /*
144     * Save away MAC address (assume this is in query info 2. If this
145     * turns out to be problematic it might be better getting it from
146     * the query info 1 packet
147     */
148    hardlen = mode->DhcpAck.Dhcpv4.BootpHwAddrLen;
149    MAC_len = hardlen > 16 ? 0 : hardlen;
150    MAC_type = mode->DhcpAck.Dhcpv4.BootpHwType;
151    memcpy(MAC, mode->DhcpAck.Dhcpv4.BootpHwAddr, MAC_len);
152
153    /*
154     * Get the boot file and other info. This lives in the CACHED_REPLY
155     * packet (query info 3)
156     */
157    parse_dhcp(&mode->PxeReply.Dhcpv4, pkt_len);
158    Print(L"\n");
159
160    /*
161     * Parse any "after" hardcoded options
162     */
163    parse_dhcp_options(embedded_dhcp_options.dhcp_data +
164		       embedded_dhcp_options.bdhcp_len,
165		       embedded_dhcp_options.adhcp_len, 0);
166
167    ip = IPInfo.myip;
168    sprintf(dst, "%u.%u.%u.%u",
169        ((const uint8_t *)&ip)[0],
170        ((const uint8_t *)&ip)[1],
171        ((const uint8_t *)&ip)[2],
172        ((const uint8_t *)&ip)[3]);
173
174    Print(L"My IP is %a\n", dst);
175}
176