1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17#include <efi_selftest.h>
18#include <net.h>
19
20
21
22
23static const u8 BROADCAST_MAC[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
24
25struct dhcp_hdr {
26 u8 op;
27#define BOOTREQUEST 1
28#define BOOTREPLY 2
29 u8 htype;
30# define HWT_ETHER 1
31 u8 hlen;
32# define HWL_ETHER 6
33 u8 hops;
34 u32 xid;
35 u16 secs;
36 u16 flags;
37#define DHCP_FLAGS_UNICAST 0x0000
38#define DHCP_FLAGS_BROADCAST 0x0080
39 u32 ciaddr;
40 u32 yiaddr;
41 u32 siaddr;
42 u32 giaddr;
43 u8 chaddr[16];
44 u8 sname[64];
45 u8 file[128];
46};
47
48
49
50
51#define DHCP_MESSAGE_TYPE 0x35
52#define DHCPDISCOVER 1
53#define DHCPOFFER 2
54#define DHCPREQUEST 3
55#define DHCPDECLINE 4
56#define DHCPACK 5
57#define DHCPNAK 6
58#define DHCPRELEASE 7
59
60struct dhcp {
61 struct ethernet_hdr eth_hdr;
62 struct ip_udp_hdr ip_udp;
63 struct dhcp_hdr dhcp_hdr;
64 u8 opt[128];
65} __packed;
66
67static struct efi_boot_services *boottime;
68static struct efi_simple_network *net;
69static struct efi_event *timer;
70static const efi_guid_t efi_net_guid = EFI_SIMPLE_NETWORK_PROTOCOL_GUID;
71
72static unsigned int net_ip_id;
73
74
75
76
77
78
79
80
81
82static unsigned int efi_ip_checksum(const void *buf, size_t len)
83{
84 size_t i;
85 u32 sum = 0;
86 const u16 *pos = buf;
87
88 for (i = 0; i < len; i += 2)
89 sum += *pos++;
90
91 sum = (sum >> 16) + (sum & 0xffff);
92 sum += sum >> 16;
93 sum = ~sum & 0xffff;
94
95 return sum;
96}
97
98
99
100
101static efi_status_t send_dhcp_discover(void)
102{
103 efi_status_t ret;
104 struct dhcp p = {};
105
106
107
108
109 boottime->copy_mem(p.eth_hdr.et_dest, (void *)BROADCAST_MAC, ARP_HLEN);
110 boottime->copy_mem(p.eth_hdr.et_src, &net->mode->current_address,
111 ARP_HLEN);
112 p.eth_hdr.et_protlen = htons(PROT_IP);
113
114
115
116 p.ip_udp.ip_hl_v = 0x45;
117 p.ip_udp.ip_len = htons(sizeof(struct dhcp) -
118 sizeof(struct ethernet_hdr));
119 p.ip_udp.ip_id = htons(++net_ip_id);
120 p.ip_udp.ip_off = htons(IP_FLAGS_DFRAG);
121 p.ip_udp.ip_ttl = 0xff;
122 p.ip_udp.ip_p = IPPROTO_UDP;
123 boottime->set_mem(&p.ip_udp.ip_dst, 4, 0xff);
124 p.ip_udp.ip_sum = efi_ip_checksum(&p.ip_udp, IP_HDR_SIZE);
125
126
127
128
129 p.ip_udp.udp_src = htons(68);
130 p.ip_udp.udp_dst = htons(67);
131 p.ip_udp.udp_len = htons(sizeof(struct dhcp) -
132 sizeof(struct ethernet_hdr) -
133 sizeof(struct ip_hdr));
134
135
136
137 p.dhcp_hdr.op = BOOTREQUEST;
138 p.dhcp_hdr.htype = HWT_ETHER;
139 p.dhcp_hdr.hlen = HWL_ETHER;
140 p.dhcp_hdr.flags = htons(DHCP_FLAGS_UNICAST);
141 boottime->copy_mem(&p.dhcp_hdr.chaddr,
142 &net->mode->current_address, ARP_HLEN);
143
144
145
146 p.opt[0] = 0x63;
147 p.opt[1] = 0x82;
148 p.opt[2] = 0x53;
149 p.opt[3] = 0x63;
150 p.opt[4] = DHCP_MESSAGE_TYPE;
151 p.opt[5] = 0x01;
152 p.opt[6] = DHCPDISCOVER;
153 p.opt[7] = 0x39;
154 p.opt[8] = 0x02;
155 p.opt[9] = 0x02;
156 p.opt[10] = 0x40;
157 p.opt[11] = 0xff;
158
159
160
161
162 ret = net->transmit(net, 0, sizeof(struct dhcp), &p, NULL, NULL, 0);
163 if (ret != EFI_SUCCESS)
164 efi_st_error("Sending a DHCP request failed\n");
165 else
166 efi_st_printf("DHCP Discover\n");
167 return ret;
168}
169
170
171
172
173
174
175
176
177
178
179
180static int setup(const efi_handle_t handle,
181 const struct efi_system_table *systable)
182{
183 efi_status_t ret;
184
185 boottime = systable->boottime;
186
187
188
189
190 ret = boottime->create_event(EVT_TIMER, TPL_CALLBACK, NULL, NULL,
191 &timer);
192 if (ret != EFI_SUCCESS) {
193 efi_st_error("Failed to create event\n");
194 return EFI_ST_FAILURE;
195 }
196
197
198
199 ret = boottime->set_timer(timer, EFI_TIMER_PERIODIC, 10000000);
200 if (ret != EFI_SUCCESS) {
201 efi_st_error("Failed to set timer\n");
202 return EFI_ST_FAILURE;
203 }
204
205
206
207 ret = boottime->locate_protocol(&efi_net_guid, NULL, (void **)&net);
208 if (ret != EFI_SUCCESS) {
209 net = NULL;
210 efi_st_error("Failed to locate simple network protocol\n");
211 return EFI_ST_FAILURE;
212 }
213
214
215
216 if (!net->mode) {
217 efi_st_error("Mode not provided\n");
218 return EFI_ST_FAILURE;
219 }
220 if (net->mode->hwaddr_size != ARP_HLEN) {
221 efi_st_error("HwAddressSize = %u, expected %u\n",
222 net->mode->hwaddr_size, ARP_HLEN);
223 return EFI_ST_FAILURE;
224 }
225
226
227
228 if (!net->wait_for_packet) {
229 efi_st_error("WaitForPacket event missing\n");
230 return EFI_ST_FAILURE;
231 }
232 if (net->mode->state == EFI_NETWORK_INITIALIZED) {
233
234
235
236 ret = net->shutdown(net);
237 if (ret != EFI_SUCCESS) {
238 efi_st_error("Failed to shut down network adapter\n");
239 return EFI_ST_FAILURE;
240 }
241 }
242 if (net->mode->state == EFI_NETWORK_STARTED) {
243
244
245
246 ret = net->stop(net);
247 if (ret != EFI_SUCCESS) {
248 efi_st_error("Failed to stop network adapter\n");
249 return EFI_ST_FAILURE;
250 }
251 }
252
253
254
255 ret = net->start(net);
256 if (ret != EFI_SUCCESS && ret != EFI_ALREADY_STARTED) {
257 efi_st_error("Failed to start network adapter\n");
258 return EFI_ST_FAILURE;
259 }
260 if (net->mode->state != EFI_NETWORK_STARTED) {
261 efi_st_error("Failed to start network adapter\n");
262 return EFI_ST_FAILURE;
263 }
264
265
266
267 ret = net->initialize(net, 0, 0);
268 if (ret != EFI_SUCCESS) {
269 efi_st_error("Failed to initialize network adapter\n");
270 return EFI_ST_FAILURE;
271 }
272 if (net->mode->state != EFI_NETWORK_INITIALIZED) {
273 efi_st_error("Failed to initialize network adapter\n");
274 return EFI_ST_FAILURE;
275 }
276 return EFI_ST_SUCCESS;
277}
278
279
280
281
282
283
284
285
286
287static int execute(void)
288{
289 efi_status_t ret;
290 struct efi_event *events[2];
291 efi_uintn_t index;
292 union {
293 struct dhcp p;
294 u8 b[PKTSIZE];
295 } buffer;
296 struct efi_mac_address srcaddr;
297 struct efi_mac_address destaddr;
298 size_t buffer_size;
299 u8 *addr;
300
301
302
303
304 unsigned int timeout = 10;
305
306
307 if (!net || !timer) {
308 efi_st_error("Cannot execute test after setup failure\n");
309 return EFI_ST_FAILURE;
310 }
311
312
313
314
315 ret = send_dhcp_discover();
316 if (ret != EFI_SUCCESS)
317 return EFI_ST_FAILURE;
318
319
320
321
322
323
324
325
326
327
328 events[0] = timer;
329 events[1] = net->wait_for_packet;
330 for (;;) {
331 u32 int_status;
332
333
334
335
336 boottime->wait_for_event(2, events, &index);
337 if (index == 0) {
338
339
340
341 --timeout;
342 if (!timeout) {
343 efi_st_error("Timeout occurred\n");
344 return EFI_ST_FAILURE;
345 }
346
347
348
349 ret = send_dhcp_discover();
350 if (ret != EFI_SUCCESS)
351 return EFI_ST_FAILURE;
352 continue;
353 }
354
355
356
357 buffer_size = sizeof(buffer);
358 ret = net->get_status(net, &int_status, NULL);
359 if (ret != EFI_SUCCESS) {
360 efi_st_error("Failed to get status");
361 return EFI_ST_FAILURE;
362 }
363 if (!(int_status & EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT)) {
364 efi_st_error("RX interrupt not set");
365 return EFI_ST_FAILURE;
366 }
367 ret = net->receive(net, NULL, &buffer_size, &buffer,
368 &srcaddr, &destaddr, NULL);
369 if (ret != EFI_SUCCESS) {
370 efi_st_error("Failed to receive packet");
371 return EFI_ST_FAILURE;
372 }
373
374
375
376
377
378 if (memcmp(&destaddr, &net->mode->current_address, ARP_HLEN) &&
379 memcmp(&destaddr, BROADCAST_MAC, ARP_HLEN))
380 continue;
381
382
383
384 if (buffer.p.eth_hdr.et_protlen != ntohs(PROT_IP) ||
385 buffer.p.ip_udp.ip_hl_v != 0x45 ||
386 buffer.p.ip_udp.ip_p != IPPROTO_UDP ||
387 buffer.p.ip_udp.udp_src != ntohs(67) ||
388 buffer.p.ip_udp.udp_dst != ntohs(68) ||
389 buffer.p.dhcp_hdr.op != BOOTREPLY)
390 continue;
391
392
393
394 break;
395 }
396
397
398
399
400 addr = (u8 *)&buffer.p.ip_udp.ip_src;
401 efi_st_printf("DHCP reply received from %u.%u.%u.%u (%pm) ",
402 addr[0], addr[1], addr[2], addr[3], &srcaddr);
403 if (!memcmp(&destaddr, BROADCAST_MAC, ARP_HLEN))
404 efi_st_printf("as broadcast message.\n");
405 else
406 efi_st_printf("as unicast message.\n");
407
408 return EFI_ST_SUCCESS;
409}
410
411
412
413
414
415
416
417
418
419static int teardown(void)
420{
421 efi_status_t ret;
422 int exit_status = EFI_ST_SUCCESS;
423
424 if (timer) {
425
426
427
428 ret = boottime->set_timer(timer, EFI_TIMER_STOP, 0);
429 if (ret != EFI_SUCCESS) {
430 efi_st_error("Failed to stop timer");
431 exit_status = EFI_ST_FAILURE;
432 }
433
434
435
436 ret = boottime->close_event(timer);
437 if (ret != EFI_SUCCESS) {
438 efi_st_error("Failed to close event");
439 exit_status = EFI_ST_FAILURE;
440 }
441 }
442 if (net) {
443
444
445
446 ret = net->shutdown(net);
447 if (ret != EFI_SUCCESS) {
448 efi_st_error("Failed to shut down network adapter\n");
449 exit_status = EFI_ST_FAILURE;
450 }
451 if (net->mode->state != EFI_NETWORK_STARTED) {
452 efi_st_error("Failed to shutdown network adapter\n");
453 return EFI_ST_FAILURE;
454 }
455
456
457
458 ret = net->stop(net);
459 if (ret != EFI_SUCCESS) {
460 efi_st_error("Failed to stop network adapter\n");
461 exit_status = EFI_ST_FAILURE;
462 }
463 if (net->mode->state != EFI_NETWORK_STOPPED) {
464 efi_st_error("Failed to stop network adapter\n");
465 return EFI_ST_FAILURE;
466 }
467 }
468
469 return exit_status;
470}
471
472EFI_UNIT_TEST(snp) = {
473 .name = "simple network protocol",
474 .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
475 .setup = setup,
476 .execute = execute,
477 .teardown = teardown,
478#ifdef CONFIG_SANDBOX
479
480
481
482
483
484 .on_request = true,
485#endif
486};
487