summaryrefslogtreecommitdiff
path: root/efi/pxe.c
blob: 6e59109b09129ee1440a52d74d98fcb83707bb01 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
/*
 * Copyright 2013-2014 Intel Corporation - All Rights Reserved
 */

#include <syslinux/firmware.h>
#include <syslinux/pxe_api.h>
#include "efi.h"
#include "net.h"
#include "fs/pxe/pxe.h"

const struct url_scheme url_schemes[] = {
    { "tftp", tftp_open, 0 },
    { "http", http_open, O_DIRECTORY },
    { "ftp",  ftp_open,  O_DIRECTORY },
    { NULL, NULL, 0 },
};

/**
 * Network stack-specific initialization
 */
void net_core_init(void)
{
    http_bake_cookies();
}

void pxe_init_isr(void) {}
void gpxe_init(void) {}
void pxe_idle_init(void) {}

int reset_pxe(void)
{
    return 0;
}

#define DNS_MAX_SERVERS 4		/* Max no of DNS servers */
uint32_t dns_server[DNS_MAX_SERVERS] = {0, };

__export uint32_t pxe_dns(const char *name)
{
    /*
     * Return failure on an empty input... this can happen during
     * some types of URL parsing, and this is the easiest place to
     * check for it.
     */
    if (!name || !*name)
	return 0;

    return 0;
}

int pxe_init(bool quiet)
{
    EFI_HANDLE *handles;
    EFI_STATUS status;
    UINTN nr_handles;

    status = LibLocateHandle(ByProtocol, &PxeBaseCodeProtocol,
			     NULL, &nr_handles, &handles);
    if (status != EFI_SUCCESS) {
	if (!quiet)
	    Print(L"No PXE Base Code Protocol\n");
	return -1;
    }

    return 0;
}

#define EDHCP_BUF_LEN 8192

struct embedded_dhcp_options {
    uint32_t magic[4];
    uint32_t bdhcp_len;
    uint32_t adhcp_len;
    uint32_t buffer_size;
    uint32_t reserved;
    uint8_t  dhcp_data[EDHCP_BUF_LEN];
} __attribute__((aligned(16)));

struct embedded_dhcp_options embedded_dhcp_options =
{
    .magic[0] = 0x2a171ead,
    .magic[1] = 0x0600e65e,
    .magic[2] = 0x4025a4e4,
    .magic[3] = 0x42388fc8,
    .bdhcp_len = 0,
    .adhcp_len = 0,
    .buffer_size = EDHCP_BUF_LEN,
};

void net_parse_dhcp(void)
{
    EFI_PXE_BASE_CODE_MODE *mode;
    EFI_PXE_BASE_CODE *bc;
    unsigned int pkt_len = sizeof(EFI_PXE_BASE_CODE_PACKET);
    EFI_STATUS status;
    uint8_t hardlen;
    uint32_t ip;
    char dst[256];

    status = uefi_call_wrapper(BS->HandleProtocol, 3, image_device_handle,
			       &PxeBaseCodeProtocol, (void **)&bc);
    if (status != EFI_SUCCESS) {
	Print(L"Failed to lookup PxeBaseCodeProtocol\n");
	return;
    }

    mode = bc->Mode;

    /*
     * Parse any "before" hardcoded options
     */
    parse_dhcp_options(embedded_dhcp_options.dhcp_data,
		       embedded_dhcp_options.bdhcp_len, 0);

    /*
     * Get the DHCP client identifiers (BIOS/PXE query info 1)
     */
    Print(L"Getting cached packet ");
    parse_dhcp(&mode->DhcpDiscover.Dhcpv4, pkt_len, 1);
    /*
     * We don't use flags from the request packet, so
     * this is a good time to initialize DHCPMagic...
     * Initialize it to 1 meaning we will accept options found;
     * in earlier versions of PXELINUX bit 0 was used to indicate
     * we have found option 208 with the appropriate magic number;
     * we no longer require that, but MAY want to re-introduce
     * it in the future for vendor encapsulated options.
     */
    *(char *)&DHCPMagic = 1;

    /*
     * Get the BOOTP/DHCP packet that brought us file (and an IP
     * address). This lives in the DHCPACK packet (BIOS/PXE query info 2)
     */
    parse_dhcp(&mode->DhcpAck.Dhcpv4, pkt_len, 2);

    /*
     * Get the boot file and other info. This lives in the CACHED_REPLY
     * packet (BIOS/PXE query info 3)
     */
    EFI_PXE_BASE_CODE_DHCPV4_PACKET*     pkt_v4 = NULL;

    if (mode->PxeReplyReceived)
	pkt_v4 = &mode->PxeReply.Dhcpv4;
    else if (mode->ProxyOfferReceived)
	pkt_v4 = &mode->ProxyOffer.Dhcpv4;

    if (pkt_v4)
	parse_dhcp(pkt_v4, pkt_len, 3);

    /*
     * Save away MAC address (assume this is in query info 2. If this
     * turns out to be problematic it might be better getting it from
     * the query info 1 packet
     */
    hardlen = mode->DhcpAck.Dhcpv4.BootpHwAddrLen;
    MAC_len = hardlen > 16 ? 0 : hardlen;
    MAC_type = mode->DhcpAck.Dhcpv4.BootpHwType;
    memcpy(MAC, mode->DhcpAck.Dhcpv4.BootpHwAddr, MAC_len);

    Print(L"\n");

    /*
     * Parse any "after" hardcoded options
     */
    parse_dhcp_options(embedded_dhcp_options.dhcp_data +
		       embedded_dhcp_options.bdhcp_len,
		       embedded_dhcp_options.adhcp_len, 0);

    ip = IPInfo.myip;
    sprintf(dst, "%u.%u.%u.%u",
        ((const uint8_t *)&ip)[0],
        ((const uint8_t *)&ip)[1],
        ((const uint8_t *)&ip)[2],
        ((const uint8_t *)&ip)[3]);

    Print(L"My IP is %a\n", dst);
    if (!(ip_ok(ip))) {
	Print(L"  NO valid IP found.\n");
    }
}