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