]> git.proxmox.com Git - mirror_edk2.git/blame - EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/support.c
Add some definitions for efi event in Uefi/UefiSpec.h to follow spec.
[mirror_edk2.git] / EdkModulePkg / Universal / Network / PxeDhcp4 / Dxe / support.c
CommitLineData
878ddf1f 1/*++\r
2\r
e5f461a8 3Copyright (c) 2006 - 2007, Intel Corporation\r
4All rights reserved. This program and the accompanying materials\r
5are licensed and made available under the terms and conditions of the BSD License\r
6which accompanies this distribution. The full text of the license may be found at\r
7http://opensource.org/licenses/bsd-license.php\r
8\r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
878ddf1f 11\r
12Module Name:\r
13 support.c\r
e5f461a8 14\r
878ddf1f 15Abstract:\r
16 Miscellaneous support routines for PxeDhcp4 protocol.\r
17\r
18--*/\r
19\r
20\r
21#include "PxeDhcp4.h"\r
22\r
23#define DebugPrint(x)\r
24//\r
25// #define DebugPrint(x) Aprint x\r
26//\r
27\r
28/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
29UINT16\r
30htons (\r
31 UINTN n\r
32 )\r
33{\r
34 return (UINT16) ((n >> 8) | (n << 8));\r
35}\r
36\r
37/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
38UINT32\r
39htonl (\r
40 UINTN n\r
41 )\r
42{\r
43 return (UINT32) ((n >> 24) | ((n >> 8) & 0xFF00) | ((n & 0xFF00) << 8) | (n << 24));\r
44}\r
45\r
46/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
47VOID\r
48EFIAPI\r
49timeout_notify (\r
50 IN EFI_EVENT Event,\r
51 IN VOID *Context\r
52 )\r
53{\r
54 ASSERT (Context);\r
55\r
56 if (Context != NULL) {\r
57 ((PXE_DHCP4_PRIVATE_DATA *) Context)->TimeoutOccurred = TRUE;\r
58 }\r
59}\r
60\r
61/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
62VOID\r
63EFIAPI\r
64periodic_notify (\r
65 IN EFI_EVENT Event,\r
66 IN VOID *Context\r
67 )\r
68{\r
69 ASSERT (Context);\r
70\r
71 if (Context != NULL) {\r
72 ((PXE_DHCP4_PRIVATE_DATA *) Context)->PeriodicOccurred = TRUE;\r
73 }\r
74}\r
75\r
76/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
77EFI_STATUS\r
78find_opt (\r
79 IN DHCP4_PACKET *Packet,\r
80 IN UINT8 OpCode,\r
81 IN UINTN Skip,\r
82 OUT DHCP4_OP **OpPtr\r
83 )\r
84/*++\r
85Routine description:\r
86 Locate option inside DHCP packet.\r
87\r
88Parameters:\r
89 Packet := Pointer to DHCP packet structure.\r
90 OpCode := Option op-code to find.\r
91 Skip := Number of found op-codes to skip.\r
92 OpPtr := Pointer to found op-code pointer.\r
93\r
94Returns:\r
95 EFI_SUCCESS := Option was found\r
96 EFI_INVALID_PARAMETER := Packet == NULL || OpPtr == NULL\r
97 EFI_INVALID_PARAMETER := OpCode == DHCP4_PAD\r
98 EFI_INVALID_PARAMETER := OpCode == DHCP4_END && Skip != 0\r
99 EFI_INVALID_PARAMETER := DHCP magik number in Packet is not valid\r
100 EFI_NOT_FOUND := op-code was not found in packet\r
101 EFI_INVALID_PARAMETER := If present, DHCP_MAX_MESSAGE_SIZE option\r
102 does not have a valid value.\r
103--*/\r
104{\r
105 UINTN msg_size;\r
106 UINTN buf_len;\r
107 UINTN n;\r
108 UINT8 *buf;\r
109 UINT8 *end_ptr;\r
110 UINT8 overload;\r
111\r
112 //\r
113 // Verify parameters.\r
114 //\r
115 if (Packet == NULL || OpPtr == NULL || OpCode == DHCP4_PAD || (OpCode == DHCP4_END && Skip != 0)) {\r
116 return EFI_INVALID_PARAMETER;\r
117 }\r
118\r
119 if (Packet->dhcp4.magik != htonl (DHCP4_MAGIK_NUMBER)) {\r
120 return EFI_INVALID_PARAMETER;\r
121 }\r
122 //\r
123 // Initialize search variables.\r
124 //\r
125 *OpPtr = NULL;\r
126\r
127 msg_size = DHCP4_MAX_PACKET_SIZE - (DHCP4_UDP_HEADER_SIZE + DHCP4_IP_HEADER_SIZE);\r
128\r
129 overload = 0;\r
130 end_ptr = NULL;\r
131\r
132 buf = Packet->dhcp4.options;\r
133 buf_len = msg_size - (Packet->dhcp4.options - Packet->raw);\r
134\r
135 //\r
136 // Start searching for requested option.\r
137 //\r
138 for (n = 0;;) {\r
139 //\r
140 // If match is found, decrement skip count and return\r
141 // when desired match is found.\r
142 //\r
143 if (buf[n] == OpCode) {\r
144 *OpPtr = (DHCP4_OP *) &buf[n];\r
145\r
146 if (Skip-- == 0) {\r
147 return EFI_SUCCESS;\r
148 }\r
149 }\r
150 //\r
151 // Skip past current option. Check for option overload\r
152 // and message size options since these will affect the\r
153 // amount of data to be searched.\r
154 //\r
155 switch (buf[n]) {\r
156 case DHCP4_PAD:\r
157 //\r
158 // Remember the first pad byte of a group. This\r
159 // could be the end of a badly formed packet.\r
160 //\r
161 if (end_ptr == NULL) {\r
162 end_ptr = &buf[n];\r
163 }\r
164\r
165 ++n;\r
166 break;\r
167\r
168 case DHCP4_END:\r
169 //\r
170 // If we reach the end we are done.\r
171 //\r
172 end_ptr = NULL;\r
173 return EFI_NOT_FOUND;\r
174\r
175 case DHCP4_OPTION_OVERLOAD:\r
176 //\r
177 // Remember the option overload value since it\r
178 // could cause the search to continue into\r
179 // the fname and sname fields.\r
180 //\r
181 end_ptr = NULL;\r
182\r
183 if (buf[n + 1] == 1) {\r
184 overload = buf[n + 2];\r
185 }\r
186\r
187 n += 2 + buf[n + 1];\r
188 break;\r
189\r
190 case DHCP4_MAX_MESSAGE_SIZE:\r
191 //\r
192 // Remember the message size value since it could\r
193 // change the amount of option buffer to search.\r
194 //\r
195 end_ptr = NULL;\r
196\r
197 if (buf[n + 1] == 2 && buf == Packet->dhcp4.options) {\r
198 msg_size = ((buf[n + 2] << 8) | buf[n + 3]) - (DHCP4_UDP_HEADER_SIZE + DHCP4_IP_HEADER_SIZE);\r
199\r
200 if (msg_size < 328) {\r
201 return EFI_INVALID_PARAMETER;\r
202 }\r
203\r
204 buf_len = msg_size - (Packet->dhcp4.options - Packet->raw);\r
205\r
206 if (n + 2 + buf[n + 1] > buf_len) {\r
207 return EFI_INVALID_PARAMETER;\r
208 }\r
209 }\r
210\r
211 /* fall thru */\r
212 default:\r
213 end_ptr = NULL;\r
214\r
215 n += 2 + buf[n + 1];\r
216 }\r
217 //\r
218 // Keep searching until the end of the buffer is reached.\r
219 //\r
220 if (n < buf_len) {\r
221 continue;\r
222 }\r
223 //\r
224 // Reached end of current buffer. Check if we are supposed\r
225 // to search the fname and sname buffers.\r
226 //\r
227 if (buf == Packet->dhcp4.options &&\r
228 (overload == DHCP4_OVERLOAD_FNAME || overload == DHCP4_OVERLOAD_FNAME_AND_SNAME)\r
229 ) {\r
230 buf = Packet->dhcp4.fname;\r
231 buf_len = 128;\r
232 n = 0;\r
233 continue;\r
234 }\r
235\r
236 if (buf != Packet->dhcp4.sname && (overload == DHCP4_OVERLOAD_SNAME || overload == DHCP4_OVERLOAD_FNAME_AND_SNAME)) {\r
237 buf = Packet->dhcp4.sname;\r
238 buf_len = 64;\r
239 n = 0;\r
240 continue;\r
241 }\r
242 //\r
243 // End of last buffer reached. If this was a search\r
244 // for the end of the options, go back to the start\r
245 // of the current pad block.\r
246 //\r
247 if (OpCode == DHCP4_END && end_ptr != NULL) {\r
248 *OpPtr = (DHCP4_OP *) end_ptr;\r
249 return EFI_SUCCESS;\r
250 }\r
251\r
252 return EFI_NOT_FOUND;\r
253 }\r
254}\r
255\r
256/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
257EFI_STATUS\r
258add_opt (\r
259 IN DHCP4_PACKET *Packet,\r
260 IN DHCP4_OP *OpPtr\r
261 )\r
262/*++\r
263Routine description:\r
264 Add option to DHCP packet.\r
265\r
266Parameters:\r
267 Packet := Pointer to DHCP packet structure.\r
268 OpPtr := Pointer to DHCP option.\r
269\r
270Returns:\r
271 EFI_INVALID_PARAMETER := Packet == NULL || OpPtr == NULL\r
272 EFI_INVALID_PARAMETER := OpPtr->op == DHCP4_PAD || OpPtr->op == DHCP4_END\r
273 EFI_INVALID_PARAMETER := DHCP magik number in DHCP packet is not valid\r
274 EFI_INVALID_PARAMETER := If DHCP_MAX_MESSAGE_SIZE option is present and\r
275 is not valid\r
276 EFI_INVALID_PARAMETER := If DHCP_OPTION_OVERLOAD option is present and\r
277 is not valid\r
278 EFI_DEVICE_ERROR := Cannot determine end of packet\r
279 EFI_BUFFER_TOO_SMALL := Not enough room in packet to add option\r
280 EFI_SUCCESS := Option added to DHCP packet\r
281--*/\r
282{\r
283 EFI_STATUS efi_status;\r
284 DHCP4_OP *msg_size_op;\r
285 DHCP4_OP *overload_op;\r
286 DHCP4_OP *op;\r
287 UINTN msg_size;\r
288 UINTN buf_len;\r
289 UINT32 magik;\r
290 UINT8 *buf;\r
291\r
292 //\r
293 // Verify parameters.\r
294 //\r
295 ASSERT (Packet);\r
296 ASSERT (OpPtr);\r
297\r
298 if (Packet == NULL || OpPtr == NULL) {\r
299 return EFI_INVALID_PARAMETER;\r
300 }\r
301\r
302 switch (OpPtr->op) {\r
303 case DHCP4_PAD:\r
304 case DHCP4_END:\r
305 //\r
306 // No adding PAD or END.\r
307 //\r
308 return EFI_INVALID_PARAMETER;\r
309 }\r
310 //\r
311 // Check the DHCP magik number.\r
312 //\r
313 CopyMem (&magik, &Packet->dhcp4.magik, 4);\r
314\r
315 if (magik != htonl (DHCP4_MAGIK_NUMBER)) {\r
316 return EFI_INVALID_PARAMETER;\r
317 }\r
318 //\r
319 // Find the DHCP message size option.\r
320 //\r
321 msg_size = DHCP4_DEFAULT_MAX_MESSAGE_SIZE;\r
322\r
323 efi_status = find_opt (\r
324 Packet,\r
325 DHCP4_MAX_MESSAGE_SIZE,\r
326 0,\r
327 &msg_size_op\r
328 );\r
329\r
330 if (EFI_ERROR (efi_status)) {\r
331 if (efi_status != EFI_NOT_FOUND) {\r
332 DebugPrint (\r
333 ("%s:%d:%r\n",\r
334 __FILE__,\r
335 __LINE__,\r
336 efi_status)\r
337 );\r
338 return efi_status;\r
339 }\r
340\r
341 msg_size_op = NULL;\r
342 } else {\r
343 CopyMem (&msg_size, msg_size_op->data, 2);\r
344 msg_size = htons (msg_size);\r
345\r
346 if (msg_size < DHCP4_DEFAULT_MAX_MESSAGE_SIZE) {\r
347 return EFI_INVALID_PARAMETER;\r
348 }\r
349 }\r
350 //\r
351 // Find the DHCP option overload option.\r
352 //\r
353 efi_status = find_opt (\r
354 Packet,\r
355 DHCP4_OPTION_OVERLOAD,\r
356 0,\r
357 &overload_op\r
358 );\r
359\r
360 if (EFI_ERROR (efi_status)) {\r
361 if (efi_status != EFI_NOT_FOUND) {\r
362 DebugPrint (\r
363 ("%s:%d:%r\n",\r
364 __FILE__,\r
365 __LINE__,\r
366 efi_status)\r
367 );\r
368 return efi_status;\r
369 }\r
370\r
371 overload_op = NULL;\r
372 } else {\r
373 if (overload_op->len != 1) {\r
374 return EFI_INVALID_PARAMETER;\r
375 }\r
376\r
377 switch (overload_op->data[0]) {\r
378 case 1:\r
379 case 2:\r
380 case 3:\r
381 break;\r
382\r
383 default:\r
384 return EFI_INVALID_PARAMETER;\r
385 }\r
386 }\r
387 //\r
388 // Find the end of the packet.\r
389 //\r
390 efi_status = find_opt (Packet, DHCP4_END, 0, &op);\r
391\r
392 if (EFI_ERROR (efi_status)) {\r
393 return EFI_INVALID_PARAMETER;\r
394 }\r
395 //\r
396 // Find which buffer the end is in.\r
397 //\r
398 if ((UINTN) op >= (UINTN) (buf = Packet->dhcp4.options)) {\r
399 buf_len = (msg_size - ((UINT8 *) &Packet->dhcp4.options - (UINT8 *) &Packet->raw)) - (DHCP4_UDP_HEADER_SIZE + DHCP4_IP_HEADER_SIZE);\r
400 } else if ((UINTN) op >= (UINTN) (buf = Packet->dhcp4.fname)) {\r
401 buf_len = 128;\r
402 } else if ((UINTN) op >= (UINTN) (buf = Packet->dhcp4.sname)) {\r
403 buf_len = 64;\r
404 } else {\r
405 return EFI_DEVICE_ERROR;\r
406 }\r
407 //\r
408 // Add option to current buffer if there is no overlow.\r
409 //\r
410 if ((UINTN) ((&op->op - buf) + 3 + op->len) < buf_len) {\r
411 CopyMem (op, OpPtr, OpPtr->len + 2);\r
412\r
413 op->data[op->len] = DHCP4_END;\r
414\r
415 return EFI_SUCCESS;\r
416 }\r
417 //\r
418 // Error if there is no space for option.\r
419 //\r
420 return EFI_BUFFER_TOO_SMALL;\r
421}\r
422\r
423/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
424EFI_STATUS\r
425start_udp (\r
426 IN PXE_DHCP4_PRIVATE_DATA *Private,\r
427 IN OPTIONAL EFI_IP_ADDRESS *StationIp,\r
428 IN OPTIONAL EFI_IP_ADDRESS *SubnetMask\r
429 )\r
430/*++\r
431Routine description:\r
432 Setup PXE BaseCode UDP stack.\r
433\r
434Parameters:\r
435 Private := Pointer to PxeDhcp4 private data.\r
436 StationIp := Pointer to IP address or NULL if not known.\r
437 SubnetMask := Pointer to subnet mask or NULL if not known.\r
438\r
439Returns:\r
440 EFI_INVALID_PARAMETER := Private == NULL || Private->PxeBc == NULL\r
441 EFI_INVALID_PARAMETER := Only one of StationIp and SubnetMask is given\r
442 EFI_SUCCESS := UDP stack is ready\r
443 other := Error from PxeBc->SetIpFilter() or PxeBc->SetStationIp()\r
444--*/\r
445{\r
446 EFI_PXE_BASE_CODE_IP_FILTER bcast_filter;\r
447 EFI_STATUS efi_status;\r
448\r
449 //\r
450 //\r
451 //\r
452 ASSERT (Private);\r
453 ASSERT (Private->PxeBc);\r
454\r
455 if (Private == NULL) {\r
456 return EFI_INVALID_PARAMETER;\r
457 }\r
458\r
459 if (Private->PxeBc == NULL) {\r
460 return EFI_INVALID_PARAMETER;\r
461 }\r
462\r
463 if (StationIp != NULL && SubnetMask == NULL) {\r
464 return EFI_INVALID_PARAMETER;\r
465 }\r
466\r
467 if (StationIp == NULL && SubnetMask != NULL) {\r
468 return EFI_INVALID_PARAMETER;\r
469 }\r
470 //\r
471 // Setup broadcast receive filter...\r
472 //\r
473 ZeroMem (&bcast_filter, sizeof (EFI_PXE_BASE_CODE_IP_FILTER));\r
474\r
475 bcast_filter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST;\r
476 bcast_filter.IpCnt = 0;\r
477\r
478 efi_status = Private->PxeBc->SetIpFilter (\r
479 Private->PxeBc,\r
480 &bcast_filter\r
481 );\r
482\r
483 if (EFI_ERROR (efi_status)) {\r
484 DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status));\r
485 return efi_status;\r
486 }\r
487 //\r
488 // Configure station IP address and subnet mask...\r
489 //\r
490 efi_status = Private->PxeBc->SetStationIp (\r
491 Private->PxeBc,\r
492 StationIp,\r
493 SubnetMask\r
494 );\r
495\r
496 if (EFI_ERROR (efi_status)) {\r
497 DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status));\r
498 }\r
499\r
500 return efi_status;\r
501}\r
502\r
503/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
504VOID\r
505stop_udp (\r
506 IN PXE_DHCP4_PRIVATE_DATA *Private\r
507 )\r
508{\r
509 //\r
510 //\r
511 //\r
512 ASSERT (Private);\r
513 ASSERT (Private->PxeBc);\r
514}\r
515\r
516/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
517EFI_STATUS\r
518start_receive_events (\r
519 IN PXE_DHCP4_PRIVATE_DATA *Private,\r
520 IN UINTN SecondsTimeout\r
521 )\r
522/*++\r
523Routine description:\r
524 Create periodic and timeout receive events.\r
525\r
526Parameters:\r
527 Private := Pointer to PxeDhcp4 private data.\r
528 SecondsTimeout := Number of seconds to wait before timeout.\r
529\r
530Returns:\r
531--*/\r
532{\r
533 EFI_STATUS efi_status;\r
534 UINTN random;\r
535\r
536 //\r
537 //\r
538 //\r
539 ASSERT (Private);\r
540 ASSERT (SecondsTimeout);\r
541\r
542 if (Private == NULL || SecondsTimeout == 0) {\r
543 return EFI_INVALID_PARAMETER;\r
544 }\r
545 //\r
546 // Need a bettern randomizer...\r
547 // For now adjust the timeout value by the least significant\r
548 // digit in the MAC address.\r
549 //\r
550 random = 0;\r
551\r
552 if (Private->PxeDhcp4.Data != NULL) {\r
553 if (Private->PxeDhcp4.Data->Discover.dhcp4.hlen != 0 && Private->PxeDhcp4.Data->Discover.dhcp4.hlen <= 16) {\r
554 random = 0xFFF & Private->PxeDhcp4.Data->Discover.dhcp4.chaddr[Private->PxeDhcp4.Data->Discover.dhcp4.hlen - 1];\r
555 }\r
556 }\r
557 //\r
558 // Setup timeout event and start timer.\r
559 //\r
560 efi_status = gBS->CreateEvent (\r
93b0fbc8 561 EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
562 TPL_NOTIFY,\r
878ddf1f 563 &timeout_notify,\r
564 Private,\r
565 &Private->TimeoutEvent\r
566 );\r
567\r
568 if (EFI_ERROR (efi_status)) {\r
569 DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status));\r
570 return efi_status;\r
571 }\r
572\r
573 efi_status = gBS->SetTimer (\r
574 Private->TimeoutEvent,\r
575 TimerRelative,\r
576 SecondsTimeout * 10000000 + random\r
577 );\r
578\r
579 if (EFI_ERROR (efi_status)) {\r
580 DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status));\r
581 gBS->CloseEvent (Private->TimeoutEvent);\r
582 return efi_status;\r
583 }\r
584\r
585 Private->TimeoutOccurred = FALSE;\r
586\r
587 //\r
588 // Setup periodic event for callbacks\r
589 //\r
590 efi_status = gBS->CreateEvent (\r
93b0fbc8 591 EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
592 TPL_NOTIFY,\r
878ddf1f 593 &periodic_notify,\r
594 Private,\r
595 &Private->PeriodicEvent\r
596 );\r
597\r
598 if (EFI_ERROR (efi_status)) {\r
599 DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status));\r
600 gBS->CloseEvent (Private->TimeoutEvent);\r
601 return efi_status;\r
602 }\r
603\r
604 efi_status = gBS->SetTimer (\r
605 Private->PeriodicEvent,\r
606 TimerPeriodic,\r
607 1000000\r
608 ); /* 1/10th second */\r
609\r
610 if (EFI_ERROR (efi_status)) {\r
611 DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status));\r
612 gBS->CloseEvent (Private->TimeoutEvent);\r
613 gBS->CloseEvent (Private->PeriodicEvent);\r
614 return efi_status;\r
615 }\r
616\r
617 Private->PeriodicOccurred = FALSE;\r
618\r
619 return EFI_SUCCESS;\r
620}\r
621\r
622/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
623VOID\r
624stop_receive_events (\r
625 IN PXE_DHCP4_PRIVATE_DATA *Private\r
626 )\r
627{\r
628 //\r
629 //\r
630 //\r
631 ASSERT (Private);\r
632\r
633 if (Private == NULL) {\r
634 return ;\r
635 }\r
636 //\r
637 //\r
638 //\r
639 gBS->CloseEvent (Private->TimeoutEvent);\r
640 Private->TimeoutOccurred = FALSE;\r
641\r
642 //\r
643 //\r
644 //\r
645 gBS->CloseEvent (Private->PeriodicEvent);\r
646 Private->PeriodicOccurred = FALSE;\r
647}\r
648\r
649/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
650EFI_STATUS\r
651tx_udp (\r
652 IN PXE_DHCP4_PRIVATE_DATA *Private,\r
653 IN EFI_IP_ADDRESS *dest_ip,\r
654 IN OPTIONAL EFI_IP_ADDRESS *gateway_ip,\r
655 IN EFI_IP_ADDRESS *src_ip,\r
656 IN VOID *buffer,\r
657 IN UINTN BufferSize\r
658 )\r
659/*++\r
660Routine description:\r
661 Transmit DHCP packet.\r
662\r
663Parameters:\r
664 Private := Pointer to PxeDhcp4 private data\r
665 dest_ip := Pointer to destination IP address\r
666 gateway_ip := Pointer to gateway IP address or NULL\r
667 src_ip := Pointer to source IP address or NULL\r
668 buffer := Pointer to buffer to transmit\r
669 BufferSize := Size of buffer in bytes\r
670\r
671Returns:\r
672 EFI_INVALID_PARAMETER := Private == NULL || dest_ip == NULL ||\r
673 buffer == NULL || BufferSize < 300 || Private->PxeBc == NULL\r
674 EFI_SUCCESS := Buffer was transmitted\r
675 other := Return from PxeBc->UdpWrite()\r
676--*/\r
677{\r
678 EFI_PXE_BASE_CODE_UDP_PORT dest_port;\r
679 EFI_PXE_BASE_CODE_UDP_PORT src_port;\r
680 EFI_IP_ADDRESS zero_ip;\r
681\r
682 //\r
683 //\r
684 //\r
685 ASSERT (Private);\r
686 ASSERT (dest_ip);\r
687 ASSERT (buffer);\r
688 ASSERT (BufferSize >= 300);\r
689\r
690 if (Private == NULL || dest_ip == NULL || buffer == NULL || BufferSize < 300) {\r
691 return EFI_INVALID_PARAMETER;\r
692 }\r
693\r
694 ASSERT (Private->PxeBc);\r
695\r
696 if (Private->PxeBc == NULL) {\r
697 return EFI_INVALID_PARAMETER;\r
698 }\r
699 //\r
700 // Transmit DHCP discover packet...\r
701 //\r
702 ZeroMem (&zero_ip, sizeof (EFI_IP_ADDRESS));\r
703\r
704 if (src_ip == NULL) {\r
705 src_ip = &zero_ip;\r
706 }\r
707\r
708 dest_port = DHCP4_SERVER_PORT;\r
709 src_port = DHCP4_CLIENT_PORT;\r
710\r
711 return Private->PxeBc->UdpWrite (\r
712 Private->PxeBc,\r
713 EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT,\r
714 dest_ip,\r
715 &dest_port,\r
716 gateway_ip,\r
717 src_ip,\r
718 &src_port,\r
719 NULL,\r
720 NULL,\r
721 &BufferSize,\r
722 buffer\r
723 );\r
724}\r
725\r
726/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
727EFI_STATUS\r
728rx_udp (\r
729 IN PXE_DHCP4_PRIVATE_DATA *Private,\r
730 OUT VOID *buffer,\r
731 IN OUT UINTN *BufferSize,\r
732 IN OUT EFI_IP_ADDRESS *dest_ip,\r
733 IN OUT EFI_IP_ADDRESS *src_ip,\r
734 IN UINT16 op_flags\r
735 )\r
736/*++\r
737Routine description:\r
738 Receive DHCP packet.\r
739\r
740Parameters:\r
741 Private := Pointer to PxeDhcp4 private data\r
742 buffer := Pointer to buffer to receive DHCP packet\r
743 BufferSize := Pointer to buffer size in bytes\r
744 dest_ip := Pointer to destination IP address\r
745 src_ip := Pointer to source IP address\r
746 op_flags := UDP receive operation flags\r
747\r
748Returns:\r
e5f461a8 749 EFI_INVALID_PARAMETER :=\r
878ddf1f 750 EFI_SUCCESS := Packet received\r
751 other := Return from PxeBc->UdpRead()\r
752--*/\r
753{\r
754 EFI_PXE_BASE_CODE_UDP_PORT dest_port;\r
755 EFI_PXE_BASE_CODE_UDP_PORT src_port;\r
756\r
757 //\r
758 //\r
759 //\r
760 ASSERT (Private);\r
761 ASSERT (buffer);\r
762 ASSERT (dest_ip);\r
763 ASSERT (src_ip);\r
764\r
765 if (Private == NULL || buffer == NULL || dest_ip == NULL || src_ip == NULL || BufferSize == NULL) {\r
766 return EFI_INVALID_PARAMETER;\r
767 }\r
768\r
769 ASSERT (Private->PxeBc);\r
770\r
771 if (Private->PxeBc == NULL) {\r
772 return EFI_INVALID_PARAMETER;\r
773 }\r
774 //\r
775 // Check for packet\r
776 //\r
777 *BufferSize = sizeof (DHCP4_PACKET);\r
778\r
779 dest_port = DHCP4_CLIENT_PORT;\r
780 src_port = DHCP4_SERVER_PORT;\r
781\r
782 return Private->PxeBc->UdpRead (\r
783 Private->PxeBc,\r
784 op_flags,\r
785 dest_ip,\r
786 &dest_port,\r
787 src_ip,\r
788 &src_port,\r
789 NULL,\r
790 NULL,\r
791 BufferSize,\r
792 buffer\r
793 );\r
794}\r
795\r
796/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
797EFI_STATUS\r
798tx_rx_udp (\r
799 IN PXE_DHCP4_PRIVATE_DATA *Private,\r
800 IN OUT EFI_IP_ADDRESS *ServerIp,\r
801 IN OPTIONAL EFI_IP_ADDRESS *gateway_ip,\r
802 IN OPTIONAL EFI_IP_ADDRESS *client_ip,\r
803 IN OPTIONAL EFI_IP_ADDRESS *SubnetMask,\r
804 IN DHCP4_PACKET *tx_pkt,\r
805 OUT DHCP4_PACKET *rx_pkt,\r
806 IN INTN (*rx_vfy)(\r
807 IN PXE_DHCP4_PRIVATE_DATA *Private,\r
808 IN DHCP4_PACKET *tx_pkt,\r
809 IN DHCP4_PACKET *rx_pkt,\r
810 IN UINTN rx_pkt_size\r
811 ),\r
812 IN UINTN SecondsTimeout\r
813 )\r
814/*++\r
815Routine description:\r
816 Transmit DHCP packet and wait for replies.\r
817\r
818Parameters:\r
819 Private := Pointer to PxeDhcp4 private data\r
820 ServerIp := Pointer to server IP address\r
821 gateway_ip := Pointer to gateway IP address or NULL\r
822 client_ip := Pointer to client IP address or NULL\r
823 SubnetMask := Pointer to subnet mask or NULL\r
824 tx_pkt := Pointer to DHCP packet to transmit\r
825 rx_pkt := Pointer to DHCP packet receive buffer\r
826 rx_vfy := Pointer to DHCP packet receive verification routine\r
827 SecondsTimeout := Number of seconds until timeout\r
828\r
829Returns:\r
e5f461a8 830 EFI_INVALID_PARAMETER := Private == NULL || ServerIp == NULL ||\r
878ddf1f 831 tx_pkt == NULL || rx_pkt == NULL || rx_vfy == NULL || Private->PxeBc == NULL\r
832 EFI_ABORTED := Receive aborted\r
833 EFI_TIMEOUT := No packets received\r
834 EFI_SUCCESS := Packet(s) received\r
835 other := Returns from other PxeDhcp4 support routines\r
836--*/\r
837{\r
838 EFI_PXE_DHCP4_CALLBACK_STATUS CallbackStatus;\r
839 EFI_IP_ADDRESS dest_ip;\r
840 EFI_IP_ADDRESS src_ip;\r
841 EFI_STATUS efi_status;\r
842 DHCP4_OP *msg_size_op;\r
843 UINTN pkt_size;\r
844 UINTN n;\r
845 UINT16 msg_size;\r
846 UINT16 op_flags;\r
847 BOOLEAN done_flag;\r
848 BOOLEAN got_packet;\r
849\r
850 //\r
851 // Bad programmer check...\r
852 //\r
853 ASSERT (Private);\r
854 ASSERT (ServerIp);\r
855 ASSERT (tx_pkt);\r
856 ASSERT (rx_pkt);\r
857 ASSERT (rx_vfy);\r
858\r
859 if (Private == NULL || ServerIp == NULL || tx_pkt == NULL || rx_pkt == NULL || rx_vfy == NULL) {\r
860 return EFI_INVALID_PARAMETER;\r
861 }\r
862\r
863 ASSERT (Private->PxeBc);\r
864\r
865 if (Private->PxeBc == NULL) {\r
866 return EFI_INVALID_PARAMETER;\r
867 }\r
868 //\r
869 // Enable UDP...\r
870 //\r
871 efi_status = start_udp (Private, client_ip, SubnetMask);\r
872\r
873 if (EFI_ERROR (efi_status)) {\r
874 DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status));\r
875 return efi_status;\r
876 }\r
877 //\r
878 // Get length of transmit packet...\r
879 //\r
880 msg_size = DHCP4_DEFAULT_MAX_MESSAGE_SIZE;\r
881\r
882 efi_status = find_opt (\r
883 tx_pkt,\r
884 DHCP4_MAX_MESSAGE_SIZE,\r
885 0,\r
886 &msg_size_op\r
887 );\r
888\r
889 if (!EFI_ERROR (efi_status)) {\r
890 CopyMem (&msg_size, msg_size_op->data, 2);\r
891\r
892 if ((msg_size = htons (msg_size)) < 328) {\r
893 msg_size = 328;\r
894 }\r
895 }\r
896 //\r
897 // Transmit packet...\r
898 //\r
899 efi_status = tx_udp (\r
900 Private,\r
901 ServerIp,\r
902 gateway_ip,\r
903 client_ip,\r
904 tx_pkt,\r
905 msg_size - (DHCP4_UDP_HEADER_SIZE + DHCP4_IP_HEADER_SIZE)\r
906 );\r
907\r
908 if (EFI_ERROR (efi_status)) {\r
909 DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status));\r
910 stop_udp (Private);\r
911 return efi_status;\r
912 }\r
913 //\r
914 // Enable periodic and timeout events...\r
915 //\r
916 efi_status = start_receive_events (Private, SecondsTimeout);\r
917\r
918 if (EFI_ERROR (efi_status)) {\r
919 DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status));\r
920 stop_udp (Private);\r
921 return efi_status;\r
922 }\r
923 //\r
924 // Wait for packet(s)...\r
925 //\r
878ddf1f 926\r
927 done_flag = FALSE;\r
928 got_packet = FALSE;\r
929\r
930 while (!done_flag) {\r
931 //\r
932 // Check for timeout event...\r
933 //\r
934 if (Private->TimeoutOccurred) {\r
935 efi_status = EFI_SUCCESS;\r
936 break;\r
937 }\r
938 //\r
939 // Check for periodic event...\r
940 //\r
941 if (Private->PeriodicOccurred && Private->callback != NULL) {\r
942 CallbackStatus = EFI_PXE_DHCP4_CALLBACK_STATUS_CONTINUE;\r
943\r
944 if (Private->callback->Callback != NULL) {\r
945 CallbackStatus = (Private->callback->Callback) (&Private->PxeDhcp4, Private->function, 0, NULL);\r
946 }\r
947\r
948 switch (CallbackStatus) {\r
949 case EFI_PXE_DHCP4_CALLBACK_STATUS_CONTINUE:\r
950 break;\r
951\r
952 case EFI_PXE_DHCP4_CALLBACK_STATUS_ABORT:\r
953 default:\r
954 stop_receive_events (Private);\r
955 stop_udp (Private);\r
956 return EFI_ABORTED;\r
957 }\r
958\r
959 Private->PeriodicOccurred = FALSE;\r
960 }\r
961 //\r
962 // Check for packet...\r
963 //\r
964 if (client_ip == NULL) {\r
965 SetMem (&dest_ip, sizeof (EFI_IP_ADDRESS), 0xFF);\r
966 } else {\r
967 CopyMem (&dest_ip, client_ip, sizeof (EFI_IP_ADDRESS));\r
968 }\r
969\r
970 SetMem (&src_ip, sizeof (EFI_IP_ADDRESS), 0xFF);\r
971\r
972 if (CompareMem (&src_ip, &ServerIp, sizeof (EFI_IP_ADDRESS))) {\r
973 ZeroMem (&src_ip, sizeof (EFI_IP_ADDRESS));\r
974 op_flags = EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP;\r
975 } else {\r
976 op_flags = 0;\r
977 }\r
978\r
979 efi_status = rx_udp (\r
980 Private,\r
981 rx_pkt,\r
982 &pkt_size,\r
983 &dest_ip,\r
984 &src_ip,\r
985 op_flags\r
986 );\r
987\r
988 if (efi_status == EFI_TIMEOUT) {\r
989 efi_status = EFI_SUCCESS;\r
990 continue;\r
991 }\r
992\r
993 if (EFI_ERROR (efi_status)) {\r
994 break;\r
995 }\r
996 //\r
997 // Some basic packet sanity checks..\r
998 //\r
999 if (pkt_size < 300) {\r
1000 continue;\r
1001 }\r
1002\r
1003 if (rx_pkt->dhcp4.op != BOOTP_REPLY) {\r
1004 continue;\r
1005 }\r
1006\r
1007 if (tx_pkt->dhcp4.htype != rx_pkt->dhcp4.htype) {\r
1008 continue;\r
1009 }\r
1010\r
1011 if ((n = tx_pkt->dhcp4.hlen) != rx_pkt->dhcp4.hlen) {\r
1012 continue;\r
1013 }\r
1014\r
1015 if (CompareMem (&tx_pkt->dhcp4.xid, &rx_pkt->dhcp4.xid, 4)) {\r
1016 continue;\r
1017 }\r
1018\r
1019 if (n != 0) {\r
1020 if (n >= 16) {\r
1021 n = 16;\r
1022 }\r
1023\r
1024 if (CompareMem (tx_pkt->dhcp4.chaddr, rx_pkt->dhcp4.chaddr, n)) {\r
1025 continue;\r
1026 }\r
1027 }\r
1028 //\r
1029 // Internal callback packet verification...\r
1030 //\r
1031 switch ((*rx_vfy) (Private, tx_pkt, rx_pkt, pkt_size)) {\r
1032 case -2: /* ignore and stop */\r
1033 stop_receive_events (Private);\r
1034 stop_udp (Private);\r
1035 return EFI_ABORTED;\r
1036\r
1037 case -1: /* ignore and wait */\r
1038 continue;\r
1039\r
1040 case 0: /* accept and wait */\r
1041 break;\r
1042\r
1043 case 1: /* accept and stop */\r
1044 done_flag = TRUE;\r
1045 break;\r
1046\r
1047 default:\r
1048 ASSERT (0);\r
1049 }\r
1050 //\r
1051 // External callback packet verification...\r
1052 //\r
1053 CallbackStatus = EFI_PXE_DHCP4_CALLBACK_STATUS_KEEP_CONTINUE;\r
1054\r
1055 if (Private->callback != NULL) {\r
1056 if (Private->callback->Callback != NULL) {\r
1057 CallbackStatus = (Private->callback->Callback) (&Private->PxeDhcp4, Private->function, (UINT32) pkt_size, rx_pkt);\r
1058 }\r
1059 }\r
1060\r
1061 switch (CallbackStatus) {\r
1062 case EFI_PXE_DHCP4_CALLBACK_STATUS_IGNORE_CONTINUE:\r
1063 continue;\r
1064\r
1065 case EFI_PXE_DHCP4_CALLBACK_STATUS_KEEP_ABORT:\r
1066 done_flag = TRUE;\r
1067 break;\r
1068\r
1069 case EFI_PXE_DHCP4_CALLBACK_STATUS_IGNORE_ABORT:\r
1070 stop_receive_events (Private);\r
1071 stop_udp (Private);\r
1072 return EFI_ABORTED;\r
1073\r
1074 case EFI_PXE_DHCP4_CALLBACK_STATUS_KEEP_CONTINUE:\r
1075 default:\r
1076 break;\r
1077 }\r
1078 //\r
1079 // We did! We did get a packet!\r
1080 //\r
1081 got_packet = TRUE;\r
1082 }\r
1083 //\r
1084 //\r
1085 //\r
1086 stop_receive_events (Private);\r
1087 stop_udp (Private);\r
1088\r
1089 if (EFI_ERROR (efi_status)) {\r
1090 DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status));\r
1091 return efi_status;\r
1092 }\r
1093\r
1094 if (got_packet) {\r
1095 return EFI_SUCCESS;\r
1096 } else {\r
1097 return EFI_TIMEOUT;\r
1098 }\r
1099}\r
1100\r
1101/* eof - support.c */\r