]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Impl.c
Scrubbed part of the code.
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Dhcp4Dxe / Dhcp4Impl.c
1 /** @file
2
3 Copyright (c) 2006 - 2008, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 Dhcp4Impl.c
15
16 Abstract:
17
18 This file implement the EFI_DHCP4_PROTOCOL interface.
19
20
21 **/
22
23
24 #include "Dhcp4Impl.h"
25
26 /**
27 Returns the current operating mode and cached data packet for the EFI DHCPv4 Protocol driver.
28
29 The GetModeData() function returns the current operating mode and cached data
30 packet for the EFI DHCPv4 Protocol driver.
31
32 @param This Pointer to the EFI_DHCP4_PROTOCOL instance.
33 @param Dhcp4ModeData Pointer to storage for the EFI_DHCP4_MODE_DATA structure.
34
35 @retval EFI_SUCCESS The mode data was returned.
36 @retval EFI_INVALID_PARAMETER This is NULL.
37
38 **/
39 EFI_STATUS
40 EFIAPI
41 EfiDhcp4GetModeData (
42 IN EFI_DHCP4_PROTOCOL *This,
43 OUT EFI_DHCP4_MODE_DATA *Dhcp4ModeData
44 );
45
46 /**
47 Initializes, changes, or resets the operational settings for the EFI DHCPv4 Protocol driver.
48
49 The Configure() function is used to initialize, change, or reset the operational
50 settings of the EFI DHCPv4 Protocol driver for the communication device on which
51 the EFI DHCPv4 Service Binding Protocol is installed. This function can be
52 successfully called only if both of the following are true:
53 * This instance of the EFI DHCPv4 Protocol driver is in the Dhcp4Stopped, Dhcp4Init,
54 Dhcp4InitReboot, or Dhcp4Bound states.
55 * No other EFI DHCPv4 Protocol driver instance that is controlled by this EFI
56 DHCPv4 Service Binding Protocol driver instance has configured this EFI DHCPv4
57 Protocol driver.
58 When this driver is in the Dhcp4Stopped state, it can transfer into one of the
59 following two possible initial states:
60 * Dhcp4Init
61 * Dhcp4InitReboot
62 The driver can transfer into these states by calling Configure() with a non-NULL
63 Dhcp4CfgData. The driver will transfer into the appropriate state based on the
64 supplied client network address in the ClientAddress parameter and DHCP options
65 in the OptionList parameter as described in RFC 2131.
66 When Configure() is called successfully while Dhcp4CfgData is set to NULL, the
67 default configuring data will be reset in the EFI DHCPv4 Protocol driver and
68 the state of the EFI DHCPv4 Protocol driver will not be changed. If one instance
69 wants to make it possible for another instance to configure the EFI DHCPv4 Protocol
70 driver, it must call this function with Dhcp4CfgData set to NULL.
71
72 @param This Pointer to the EFI_DHCP4_PROTOCOL instance.
73 @param Dhcp4CfgData Pointer to the EFI_DHCP4_CONFIG_DATA.
74
75 @retval EFI_SUCCESS The EFI DHCPv4 Protocol driver is now in the Dhcp4Init or
76 Dhcp4InitReboot state, if the original state of this driver
77 was Dhcp4Stopped and the value of Dhcp4CfgData was
78 not NULL. Otherwise, the state was left unchanged.
79 @retval EFI_ACCESS_DENIED This instance of the EFI DHCPv4 Protocol driver was not in the
80 Dhcp4Stopped, Dhcp4Init, Dhcp4InitReboot, or Dhcp4Bound state;
81 Or onother instance of this EFI DHCPv4 Protocol driver is already
82 in a valid configured state.
83 @retval EFI_INVALID_PARAMETER Some parameter is NULL.
84 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
85 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
86
87 **/
88 EFI_STATUS
89 EFIAPI
90 EfiDhcp4Configure (
91 IN EFI_DHCP4_PROTOCOL *This,
92 IN EFI_DHCP4_CONFIG_DATA *Dhcp4CfgData OPTIONAL
93 );
94
95 /**
96 Starts the DHCP configuration process.
97
98 The Start() function starts the DHCP configuration process. This function can
99 be called only when the EFI DHCPv4 Protocol driver is in the Dhcp4Init or
100 Dhcp4InitReboot state.
101 If the DHCP process completes successfully, the state of the EFI DHCPv4 Protocol
102 driver will be transferred through Dhcp4Selecting and Dhcp4Requesting to the
103 Dhcp4Bound state. The CompletionEvent will then be signaled if it is not NULL.
104 If the process aborts, either by the user or by some unexpected network error,
105 the state is restored to the Dhcp4Init state. The Start() function can be called
106 again to restart the process.
107 Refer to RFC 2131 for precise state transitions during this process. At the
108 time when each event occurs in this process, the callback function that was set
109 by EFI_DHCP4_PROTOCOL.Configure() will be called and the user can take this
110 opportunity to control the process.
111
112 @param This Pointer to the EFI_DHCP4_PROTOCOL instance.
113 @param CompletionEvent If not NULL, indicates the event that will be signaled when the
114 EFI DHCPv4 Protocol driver is transferred into the
115 Dhcp4Bound state or when the DHCP process is aborted.
116 EFI_DHCP4_PROTOCOL.GetModeData() can be called to
117 check the completion status. If NULL,
118 EFI_DHCP4_PROTOCOL.Start() will wait until the driver
119 is transferred into the Dhcp4Bound state or the process fails.
120
121 @retval EFI_SUCCESS The DHCP configuration process has started, or it has completed
122 when CompletionEvent is NULL.
123 @retval EFI_NOT_STARTED The EFI DHCPv4 Protocol driver is in the Dhcp4Stopped
124 state. EFI_DHCP4_PROTOCOL. Configure() needs to be called.
125 @retval EFI_INVALID_PARAMETER This is NULL.
126 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
127 @retval EFI_TIMEOUT The DHCP configuration process failed because no response was
128 received from the server within the specified timeout value.
129 @retval EFI_ABORTED The user aborted the DHCP process.
130 @retval EFI_ALREADY_STARTED Some other EFI DHCPv4 Protocol instance already started the
131 DHCP process.
132 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
133
134 **/
135 EFI_STATUS
136 EFIAPI
137 EfiDhcp4Start (
138 IN EFI_DHCP4_PROTOCOL *This,
139 IN EFI_EVENT CompletionEvent OPTIONAL
140 );
141
142 /**
143 Extends the lease time by sending a request packet.
144
145 The RenewRebind() function is used to manually extend the lease time when the
146 EFI DHCPv4 Protocol driver is in the Dhcp4Bound state and the lease time has
147 not expired yet. This function will send a request packet to the previously
148 found server (or to any server when RebindRequest is TRUE) and transfer the
149 state into the Dhcp4Renewing state (or Dhcp4Rebinding when RebindingRequest is
150 TRUE). When a response is received, the state is returned to Dhcp4Bound.
151 If no response is received before the try count is exceeded (the RequestTryCount
152 field that is specified in EFI_DHCP4_CONFIG_DATA) but before the lease time that
153 was issued by the previous server expires, the driver will return to the Dhcp4Bound
154 state and the previous configuration is restored. The outgoing and incoming packets
155 can be captured by the EFI_DHCP4_CALLBACK function.
156
157 @param This Pointer to the EFI_DHCP4_PROTOCOL instance.
158 @param RebindRequest If TRUE, this function broadcasts the request packets and enters
159 the Dhcp4Rebinding state. Otherwise, it sends a unicast
160 request packet and enters the Dhcp4Renewing state.
161 @param CompletionEvent If not NULL, this event is signaled when the renew/rebind phase
162 completes or some error occurs.
163 EFI_DHCP4_PROTOCOL.GetModeData() can be called to
164 check the completion status. If NULL,
165 EFI_DHCP4_PROTOCOL.RenewRebind() will busy-wait
166 until the DHCP process finishes.
167
168 @retval EFI_SUCCESS The EFI DHCPv4 Protocol driver is now in the
169 Dhcp4Renewing state or is back to the Dhcp4Bound state.
170 @retval EFI_NOT_STARTED The EFI DHCPv4 Protocol driver is in the Dhcp4Stopped
171 state. EFI_DHCP4_PROTOCOL.Configure() needs to
172 be called.
173 @retval EFI_INVALID_PARAMETER This is NULL.
174 @retval EFI_TIMEOUT There was no response from the server when the try count was
175 exceeded.
176 @retval EFI_ACCESS_DENIED The driver is not in the Dhcp4Bound state.
177 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
178
179 **/
180 EFI_STATUS
181 EFIAPI
182 EfiDhcp4RenewRebind (
183 IN EFI_DHCP4_PROTOCOL *This,
184 IN BOOLEAN RebindRequest,
185 IN EFI_EVENT CompletionEvent OPTIONAL
186 );
187
188 /**
189 Releases the current address configuration.
190
191 The Release() function releases the current configured IP address by doing either
192 of the following:
193 * Sending a DHCPRELEASE packet when the EFI DHCPv4 Protocol driver is in the
194 Dhcp4Bound state
195 * Setting the previously assigned IP address that was provided with the
196 EFI_DHCP4_PROTOCOL.Configure() function to 0.0.0.0 when the driver is in
197 Dhcp4InitReboot state
198 After a successful call to this function, the EFI DHCPv4 Protocol driver returns
199 to the Dhcp4Init state and any subsequent incoming packets will be discarded silently.
200
201 @param This Pointer to the EFI_DHCP4_PROTOCOL instance.
202
203 @retval EFI_SUCCESS The EFI DHCPv4 Protocol driver is now in the Dhcp4Init phase.
204 @retval EFI_INVALID_PARAMETER This is NULL.
205 @retval EFI_ACCESS_DENIED The EFI DHCPv4 Protocol driver is not Dhcp4InitReboot state.
206 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
207
208 **/
209 EFI_STATUS
210 EFIAPI
211 EfiDhcp4Release (
212 IN EFI_DHCP4_PROTOCOL *This
213 );
214
215 /**
216 Stops the current address configuration.
217
218 The Stop() function is used to stop the DHCP configuration process. After this
219 function is called successfully, the EFI DHCPv4 Protocol driver is transferred
220 into the Dhcp4Stopped state. EFI_DHCP4_PROTOCOL.Configure() needs to be called
221 before DHCP configuration process can be started again. This function can be
222 called when the EFI DHCPv4 Protocol driver is in any state.
223
224 @param This Pointer to the EFI_DHCP4_PROTOCOL instance.
225
226 @retval EFI_SUCCESS The EFI DHCPv4 Protocol driver is now in the Dhcp4Stopped phase.
227 @retval EFI_INVALID_PARAMETER This is NULL.
228
229 **/
230 EFI_STATUS
231 EFIAPI
232 EfiDhcp4Stop (
233 IN EFI_DHCP4_PROTOCOL *This
234 );
235
236 /**
237 Builds a DHCP packet, given the options to be appended or deleted or replaced.
238
239 The Build() function is used to assemble a new packet from the original packet
240 by replacing or deleting existing options or appending new options. This function
241 does not change any state of the EFI DHCPv4 Protocol driver and can be used at
242 any time.
243
244 @param This Pointer to the EFI_DHCP4_PROTOCOL instance.
245 @param SeedPacket Initial packet to be used as a base for building new packet.
246 @param DeleteCount Number of opcodes in the DeleteList.
247 @param DeleteList List of opcodes to be deleted from the seed packet.
248 Ignored if DeleteCount is zero.
249 @param AppendCount Number of entries in the OptionList.
250 @param AppendList Pointer to a DHCP option list to be appended to SeedPacket.
251 If SeedPacket also contains options in this list, they are
252 replaced by new options (except pad option). Ignored if
253 AppendCount is zero. Type EFI_DHCP4_PACKET_OPTION
254 @param NewPacket Pointer to storage for the pointer to the new allocated packet.
255 Use the EFI Boot Service FreePool() on the resulting pointer
256 when done with the packet.
257
258 @retval EFI_SUCCESS The new packet was built.
259 @retval EFI_OUT_OF_RESOURCES Storage for the new packet could not be allocated.
260 @retval EFI_INVALID_PARAMETER Some parameter is NULL.
261
262 **/
263 EFI_STATUS
264 EFIAPI
265 EfiDhcp4Build (
266 IN EFI_DHCP4_PROTOCOL *This,
267 IN EFI_DHCP4_PACKET *SeedPacket,
268 IN UINT32 DeleteCount,
269 IN UINT8 *DeleteList OPTIONAL,
270 IN UINT32 AppendCount,
271 IN EFI_DHCP4_PACKET_OPTION *AppendList[] OPTIONAL,
272 OUT EFI_DHCP4_PACKET **NewPacket
273 );
274
275 /**
276 Transmits a DHCP formatted packet and optionally waits for responses.
277
278 The TransmitReceive() function is used to transmit a DHCP packet and optionally
279 wait for the response from servers. This function does not change the state of
280 the EFI DHCPv4 Protocol driver and thus can be used at any time.
281
282 @param This Pointer to the EFI_DHCP4_PROTOCOL instance.
283 @param Token Pointer to the EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN structure.
284
285 @retval EFI_SUCCESS The packet was successfully queued for transmission.
286 @retval EFI_INVALID_PARAMETER Some parameter is NULL.
287 @retval EFI_NOT_READY The previous call to this function has not finished yet. Try to call
288 this function after collection process completes.
289 @retval EFI_NO_MAPPING The default station address is not available yet.
290 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
291 @retval Others Some other unexpected error occurred.
292
293 **/
294 EFI_STATUS
295 EFIAPI
296 EfiDhcp4TransmitReceive (
297 IN EFI_DHCP4_PROTOCOL *This,
298 IN EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN *Token
299 );
300
301 /**
302 Parses the packed DHCP option data.
303
304 The Parse() function is used to retrieve the option list from a DHCP packet.
305 If *OptionCount isn’t zero, and there is enough space for all the DHCP options
306 in the Packet, each element of PacketOptionList is set to point to somewhere in
307 the Packet->Dhcp4.Option where a new DHCP option begins. If RFC3396 is supported,
308 the caller should reassemble the parsed DHCP options to get the finial result.
309 If *OptionCount is zero or there isn’t enough space for all of them, the number
310 of DHCP options in the Packet is returned in OptionCount.
311
312 @param This Pointer to the EFI_DHCP4_PROTOCOL instance.
313 @param Packet Pointer to packet to be parsed.
314 @param OptionCount On input, the number of entries in the PacketOptionList.
315 On output, the number of entries that were written into the
316 PacketOptionList.
317 @param PacketOptionList List of packet option entries to be filled in. End option or pad
318 options are not included.
319
320 @retval EFI_SUCCESS The packet was successfully parsed.
321 @retval EFI_INVALID_PARAMETER Some parameter is NULL.
322 @retval EFI_BUFFER_TOO_SMALL One or more of the following conditions is TRUE:
323 1) *OptionCount is smaller than the number of options that
324 were found in the Packet.
325 2) PacketOptionList is NULL.
326
327 **/
328 EFI_STATUS
329 EFIAPI
330 EfiDhcp4Parse (
331 IN EFI_DHCP4_PROTOCOL *This,
332 IN EFI_DHCP4_PACKET *Packet,
333 IN OUT UINT32 *OptionCount,
334 OUT EFI_DHCP4_PACKET_OPTION *PacketOptionList[] OPTIONAL
335 );
336
337 EFI_DHCP4_PROTOCOL mDhcp4ProtocolTemplate = {
338 EfiDhcp4GetModeData,
339 EfiDhcp4Configure,
340 EfiDhcp4Start,
341 EfiDhcp4RenewRebind,
342 EfiDhcp4Release,
343 EfiDhcp4Stop,
344 EfiDhcp4Build,
345 EfiDhcp4TransmitReceive,
346 EfiDhcp4Parse
347 };
348
349 /**
350 Returns the current operating mode and cached data packet for the EFI DHCPv4 Protocol driver.
351
352 The GetModeData() function returns the current operating mode and cached data
353 packet for the EFI DHCPv4 Protocol driver.
354
355 @param This Pointer to the EFI_DHCP4_PROTOCOL instance.
356 @param Dhcp4ModeData Pointer to storage for the EFI_DHCP4_MODE_DATA structure.
357
358 @retval EFI_SUCCESS The mode data was returned.
359 @retval EFI_INVALID_PARAMETER This is NULL.
360
361 **/
362 EFI_STATUS
363 EFIAPI
364 EfiDhcp4GetModeData (
365 IN EFI_DHCP4_PROTOCOL *This,
366 OUT EFI_DHCP4_MODE_DATA *Dhcp4ModeData
367 )
368 {
369 DHCP_PROTOCOL *Instance;
370 DHCP_SERVICE *DhcpSb;
371 DHCP_PARAMETER *Para;
372 EFI_TPL OldTpl;
373 IP4_ADDR Ip;
374
375 //
376 // First validate the parameters.
377 //
378 if ((This == NULL) || (Dhcp4ModeData == NULL)) {
379 return EFI_INVALID_PARAMETER;
380 }
381
382 Instance = DHCP_INSTANCE_FROM_THIS (This);
383
384 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
385 DhcpSb = Instance->Service;
386
387 //
388 // Caller can use GetModeData to retrieve current DHCP states
389 // no matter whether it is the active child or not.
390 //
391 Dhcp4ModeData->State = (EFI_DHCP4_STATE) DhcpSb->DhcpState;
392 CopyMem (&Dhcp4ModeData->ConfigData, &DhcpSb->ActiveConfig, sizeof (Dhcp4ModeData->ConfigData));
393 CopyMem (&Dhcp4ModeData->ClientMacAddress, &DhcpSb->Mac, sizeof (Dhcp4ModeData->ClientMacAddress));
394
395 Ip = HTONL (DhcpSb->ClientAddr);
396 CopyMem (&Dhcp4ModeData->ClientAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));
397
398 Ip = HTONL (DhcpSb->Netmask);
399 CopyMem (&Dhcp4ModeData->SubnetMask, &Ip, sizeof (EFI_IPv4_ADDRESS));
400
401 Ip = HTONL (DhcpSb->ServerAddr);
402 CopyMem (&Dhcp4ModeData->ServerAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));
403
404 Para = DhcpSb->Para;
405
406 if (Para != NULL) {
407 Ip = HTONL (Para->Router);
408 CopyMem (&Dhcp4ModeData->RouterAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));
409 Dhcp4ModeData->LeaseTime = Para->Lease;
410 } else {
411 ZeroMem (&Dhcp4ModeData->RouterAddress, sizeof (EFI_IPv4_ADDRESS));
412 Dhcp4ModeData->LeaseTime = 0xffffffff;
413 }
414
415 Dhcp4ModeData->ReplyPacket = DhcpSb->Selected;
416
417 gBS->RestoreTPL (OldTpl);
418 return EFI_SUCCESS;
419 }
420
421
422 /**
423 Free the resource related to the configure parameters.
424 DHCP driver will make a copy of the user's configure
425 such as the time out value.
426
427 @param Config The DHCP configure data
428
429 @return None
430
431 **/
432 VOID
433 DhcpCleanConfigure (
434 IN OUT EFI_DHCP4_CONFIG_DATA *Config
435 )
436 {
437 UINT32 Index;
438
439 if (Config->DiscoverTimeout != NULL) {
440 gBS->FreePool (Config->DiscoverTimeout);
441 }
442
443 if (Config->RequestTimeout != NULL) {
444 gBS->FreePool (Config->RequestTimeout);
445 }
446
447 if (Config->OptionList != NULL) {
448 for (Index = 0; Index < Config->OptionCount; Index++) {
449 if (Config->OptionList[Index] != NULL) {
450 gBS->FreePool (Config->OptionList[Index]);
451 }
452 }
453
454 gBS->FreePool (Config->OptionList);
455 }
456
457 ZeroMem (Config, sizeof (EFI_DHCP4_CONFIG_DATA));
458 }
459
460
461 /**
462 Allocate memory for configure parameter such as timeout value for Dst,
463 then copy the configure parameter from Src to Dst.
464
465 @param Dst The destination DHCP configure data.
466 @param Src The source DHCP configure data.
467
468 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
469 @retval EFI_SUCCESS The configure is copied.
470
471 **/
472 EFI_STATUS
473 DhcpCopyConfigure (
474 OUT EFI_DHCP4_CONFIG_DATA *Dst,
475 IN EFI_DHCP4_CONFIG_DATA *Src
476 )
477 {
478 EFI_DHCP4_PACKET_OPTION **DstOptions;
479 EFI_DHCP4_PACKET_OPTION **SrcOptions;
480 INTN Len;
481 UINT32 Index;
482
483 CopyMem (Dst, Src, sizeof (*Dst));
484 Dst->DiscoverTimeout = NULL;
485 Dst->RequestTimeout = NULL;
486 Dst->OptionList = NULL;
487
488 //
489 // Allocate a memory then copy DiscoverTimeout to it
490 //
491 if (Src->DiscoverTimeout != NULL) {
492 Len = Src->DiscoverTryCount * sizeof (UINT32);
493 Dst->DiscoverTimeout = AllocatePool (Len);
494
495 if (Dst->DiscoverTimeout == NULL) {
496 return EFI_OUT_OF_RESOURCES;
497 }
498
499 for (Index = 0; Index < Src->DiscoverTryCount; Index++) {
500 Dst->DiscoverTimeout[Index] = MAX (Src->DiscoverTimeout[Index], 1);
501 }
502 }
503
504 //
505 // Allocate a memory then copy RequestTimeout to it
506 //
507 if (Src->RequestTimeout != NULL) {
508 Len = Src->RequestTryCount * sizeof (UINT32);
509 Dst->RequestTimeout = AllocatePool (Len);
510
511 if (Dst->RequestTimeout == NULL) {
512 goto ON_ERROR;
513 }
514
515 for (Index = 0; Index < Src->RequestTryCount; Index++) {
516 Dst->RequestTimeout[Index] = MAX (Src->RequestTimeout[Index], 1);
517 }
518 }
519
520 //
521 // Allocate an array of dhcp option point, then allocate memory
522 // for each option and copy the source option to it
523 //
524 if (Src->OptionList != NULL) {
525 Len = Src->OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *);
526 Dst->OptionList = AllocateZeroPool (Len);
527
528 if (Dst->OptionList == NULL) {
529 goto ON_ERROR;
530 }
531
532 DstOptions = Dst->OptionList;
533 SrcOptions = Src->OptionList;
534
535 for (Index = 0; Index < Src->OptionCount; Index++) {
536 Len = sizeof (EFI_DHCP4_PACKET_OPTION) + MAX (SrcOptions[Index]->Length - 1, 0);
537
538 DstOptions[Index] = AllocatePool (Len);
539
540 if (DstOptions[Index] == NULL) {
541 goto ON_ERROR;
542 }
543
544 CopyMem (DstOptions[Index], SrcOptions[Index], Len);
545 }
546 }
547
548 return EFI_SUCCESS;
549
550 ON_ERROR:
551 DhcpCleanConfigure (Dst);
552 return EFI_OUT_OF_RESOURCES;
553 }
554
555
556 /**
557 Give up the control of the DHCP service to let other child
558 resume. Don't change the service's DHCP state and the Client
559 address and option list configure as required by RFC2131.
560
561 @param DhcpSb The DHCP service instance.
562
563 @return None
564
565 **/
566 VOID
567 DhcpYieldControl (
568 IN DHCP_SERVICE *DhcpSb
569 )
570 {
571 EFI_DHCP4_CONFIG_DATA *Config;
572
573 Config = &DhcpSb->ActiveConfig;
574
575 DhcpSb->ServiceState = DHCP_UNCONFIGED;
576 DhcpSb->ActiveChild = NULL;
577
578 if (Config->DiscoverTimeout != NULL) {
579 gBS->FreePool (Config->DiscoverTimeout);
580
581 Config->DiscoverTryCount = 0;
582 Config->DiscoverTimeout = NULL;
583 }
584
585 if (Config->RequestTimeout != NULL) {
586 gBS->FreePool (Config->RequestTimeout);
587
588 Config->RequestTryCount = 0;
589 Config->RequestTimeout = NULL;
590 }
591
592 Config->Dhcp4Callback = NULL;
593 Config->CallbackContext = NULL;
594 }
595
596
597 /**
598 Initializes, changes, or resets the operational settings for the EFI DHCPv4 Protocol driver.
599
600 The Configure() function is used to initialize, change, or reset the operational
601 settings of the EFI DHCPv4 Protocol driver for the communication device on which
602 the EFI DHCPv4 Service Binding Protocol is installed. This function can be
603 successfully called only if both of the following are true:
604 * This instance of the EFI DHCPv4 Protocol driver is in the Dhcp4Stopped, Dhcp4Init,
605 Dhcp4InitReboot, or Dhcp4Bound states.
606 * No other EFI DHCPv4 Protocol driver instance that is controlled by this EFI
607 DHCPv4 Service Binding Protocol driver instance has configured this EFI DHCPv4
608 Protocol driver.
609 When this driver is in the Dhcp4Stopped state, it can transfer into one of the
610 following two possible initial states:
611 * Dhcp4Init
612 * Dhcp4InitReboot
613 The driver can transfer into these states by calling Configure() with a non-NULL
614 Dhcp4CfgData. The driver will transfer into the appropriate state based on the
615 supplied client network address in the ClientAddress parameter and DHCP options
616 in the OptionList parameter as described in RFC 2131.
617 When Configure() is called successfully while Dhcp4CfgData is set to NULL, the
618 default configuring data will be reset in the EFI DHCPv4 Protocol driver and
619 the state of the EFI DHCPv4 Protocol driver will not be changed. If one instance
620 wants to make it possible for another instance to configure the EFI DHCPv4 Protocol
621 driver, it must call this function with Dhcp4CfgData set to NULL.
622
623 @param This Pointer to the EFI_DHCP4_PROTOCOL instance.
624 @param Dhcp4CfgData Pointer to the EFI_DHCP4_CONFIG_DATA.
625
626 @retval EFI_SUCCESS The EFI DHCPv4 Protocol driver is now in the Dhcp4Init or
627 Dhcp4InitReboot state, if the original state of this driver
628 was Dhcp4Stopped and the value of Dhcp4CfgData was
629 not NULL. Otherwise, the state was left unchanged.
630 @retval EFI_ACCESS_DENIED This instance of the EFI DHCPv4 Protocol driver was not in the
631 Dhcp4Stopped, Dhcp4Init, Dhcp4InitReboot, or Dhcp4Bound state;
632 Or onother instance of this EFI DHCPv4 Protocol driver is already
633 in a valid configured state.
634 @retval EFI_INVALID_PARAMETER Some parameter is NULL.
635 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
636 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
637
638 **/
639 EFI_STATUS
640 EFIAPI
641 EfiDhcp4Configure (
642 IN EFI_DHCP4_PROTOCOL *This,
643 IN EFI_DHCP4_CONFIG_DATA *Dhcp4CfgData OPTIONAL
644 )
645 {
646 EFI_DHCP4_CONFIG_DATA *Config;
647 DHCP_PROTOCOL *Instance;
648 DHCP_SERVICE *DhcpSb;
649 EFI_STATUS Status;
650 EFI_TPL OldTpl;
651 UINT32 Index;
652 IP4_ADDR Ip;
653
654 //
655 // First validate the parameters
656 //
657 if (This == NULL) {
658 return EFI_INVALID_PARAMETER;
659 }
660
661 if (Dhcp4CfgData != NULL) {
662 if (Dhcp4CfgData->DiscoverTryCount && (Dhcp4CfgData->DiscoverTimeout == NULL)) {
663 return EFI_INVALID_PARAMETER;
664 }
665
666 if (Dhcp4CfgData->RequestTryCount && (Dhcp4CfgData->RequestTimeout == NULL)) {
667 return EFI_INVALID_PARAMETER;
668 }
669
670 if (Dhcp4CfgData->OptionCount && (Dhcp4CfgData->OptionList == NULL)) {
671 return EFI_INVALID_PARAMETER;
672 }
673
674 CopyMem (&Ip, &Dhcp4CfgData->ClientAddress, sizeof (IP4_ADDR));
675
676 if ((Ip != 0) && !Ip4IsUnicast (NTOHL (Ip), 0)) {
677
678 return EFI_INVALID_PARAMETER;
679 }
680 }
681
682 Instance = DHCP_INSTANCE_FROM_THIS (This);
683
684 if (Instance->Signature != DHCP_PROTOCOL_SIGNATURE) {
685 return EFI_INVALID_PARAMETER;
686 }
687
688 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
689
690 DhcpSb = Instance->Service;
691 Config = &DhcpSb->ActiveConfig;
692
693 Status = EFI_ACCESS_DENIED;
694
695 if ((DhcpSb->DhcpState != Dhcp4Stopped) &&
696 (DhcpSb->DhcpState != Dhcp4Init) &&
697 (DhcpSb->DhcpState != Dhcp4InitReboot) &&
698 (DhcpSb->DhcpState != Dhcp4Bound)) {
699
700 goto ON_EXIT;
701 }
702
703 if ((DhcpSb->ActiveChild != NULL) && (DhcpSb->ActiveChild != Instance)) {
704 goto ON_EXIT;
705 }
706
707 if (Dhcp4CfgData != NULL) {
708 Status = EFI_OUT_OF_RESOURCES;
709 DhcpCleanConfigure (Config);
710
711 if (EFI_ERROR (DhcpCopyConfigure (Config, Dhcp4CfgData))) {
712 goto ON_EXIT;
713 }
714
715 DhcpSb->UserOptionLen = 0;
716
717 for (Index = 0; Index < Dhcp4CfgData->OptionCount; Index++) {
718 DhcpSb->UserOptionLen += Dhcp4CfgData->OptionList[Index]->Length + 2;
719 }
720
721 DhcpSb->ActiveChild = Instance;
722
723 if (DhcpSb->DhcpState == Dhcp4Stopped) {
724 DhcpSb->ClientAddr = EFI_NTOHL (Dhcp4CfgData->ClientAddress);
725
726 if (DhcpSb->ClientAddr != 0) {
727 DhcpSb->DhcpState = Dhcp4InitReboot;
728 } else {
729 DhcpSb->DhcpState = Dhcp4Init;
730 }
731 }
732
733 DhcpSb->ServiceState = DHCP_CONFIGED;
734 Status = EFI_SUCCESS;
735
736 } else if (DhcpSb->ActiveChild == Instance) {
737 Status = EFI_SUCCESS;
738 DhcpYieldControl (DhcpSb);
739 }
740
741 ON_EXIT:
742 gBS->RestoreTPL (OldTpl);
743 return Status;
744 }
745
746
747 /**
748 Starts the DHCP configuration process.
749
750 The Start() function starts the DHCP configuration process. This function can
751 be called only when the EFI DHCPv4 Protocol driver is in the Dhcp4Init or
752 Dhcp4InitReboot state.
753 If the DHCP process completes successfully, the state of the EFI DHCPv4 Protocol
754 driver will be transferred through Dhcp4Selecting and Dhcp4Requesting to the
755 Dhcp4Bound state. The CompletionEvent will then be signaled if it is not NULL.
756 If the process aborts, either by the user or by some unexpected network error,
757 the state is restored to the Dhcp4Init state. The Start() function can be called
758 again to restart the process.
759 Refer to RFC 2131 for precise state transitions during this process. At the
760 time when each event occurs in this process, the callback function that was set
761 by EFI_DHCP4_PROTOCOL.Configure() will be called and the user can take this
762 opportunity to control the process.
763
764 @param This Pointer to the EFI_DHCP4_PROTOCOL instance.
765 @param CompletionEvent If not NULL, indicates the event that will be signaled when the
766 EFI DHCPv4 Protocol driver is transferred into the
767 Dhcp4Bound state or when the DHCP process is aborted.
768 EFI_DHCP4_PROTOCOL.GetModeData() can be called to
769 check the completion status. If NULL,
770 EFI_DHCP4_PROTOCOL.Start() will wait until the driver
771 is transferred into the Dhcp4Bound state or the process fails.
772
773 @retval EFI_SUCCESS The DHCP configuration process has started, or it has completed
774 when CompletionEvent is NULL.
775 @retval EFI_NOT_STARTED The EFI DHCPv4 Protocol driver is in the Dhcp4Stopped
776 state. EFI_DHCP4_PROTOCOL. Configure() needs to be called.
777 @retval EFI_INVALID_PARAMETER This is NULL.
778 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
779 @retval EFI_TIMEOUT The DHCP configuration process failed because no response was
780 received from the server within the specified timeout value.
781 @retval EFI_ABORTED The user aborted the DHCP process.
782 @retval EFI_ALREADY_STARTED Some other EFI DHCPv4 Protocol instance already started the
783 DHCP process.
784 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
785
786 **/
787 EFI_STATUS
788 EFIAPI
789 EfiDhcp4Start (
790 IN EFI_DHCP4_PROTOCOL *This,
791 IN EFI_EVENT CompletionEvent OPTIONAL
792 )
793 {
794 DHCP_PROTOCOL *Instance;
795 DHCP_SERVICE *DhcpSb;
796 EFI_STATUS Status;
797 EFI_TPL OldTpl;
798
799 //
800 // First validate the parameters
801 //
802 if (This == NULL) {
803 return EFI_INVALID_PARAMETER;
804 }
805
806 Instance = DHCP_INSTANCE_FROM_THIS (This);
807
808 if (Instance->Signature != DHCP_PROTOCOL_SIGNATURE) {
809 return EFI_INVALID_PARAMETER;
810 }
811
812 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
813 DhcpSb = Instance->Service;
814
815 if (DhcpSb->DhcpState == Dhcp4Stopped) {
816 Status = EFI_NOT_STARTED;
817 goto ON_ERROR;
818 }
819
820 if ((DhcpSb->DhcpState != Dhcp4Init) && (DhcpSb->DhcpState != Dhcp4InitReboot)) {
821 Status = EFI_ALREADY_STARTED;
822 goto ON_ERROR;
823 }
824
825 DhcpSb->IoStatus = EFI_ALREADY_STARTED;
826
827 if (EFI_ERROR (Status = DhcpInitRequest (DhcpSb))) {
828 goto ON_ERROR;
829 }
830
831 //
832 // Start/Restart the receiving.
833 //
834 Status = UdpIoRecvDatagram (DhcpSb->UdpIo, DhcpInput, DhcpSb, 0);
835
836 if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
837 goto ON_ERROR;
838 }
839
840 Instance->CompletionEvent = CompletionEvent;
841
842 //
843 // Restore the TPL now, don't call poll function at TPL_CALLBACK.
844 //
845 gBS->RestoreTPL (OldTpl);
846
847 if (CompletionEvent == NULL) {
848 while (DhcpSb->IoStatus == EFI_ALREADY_STARTED) {
849 DhcpSb->UdpIo->Udp->Poll (DhcpSb->UdpIo->Udp);
850 }
851
852 return DhcpSb->IoStatus;
853 }
854
855 return EFI_SUCCESS;
856
857 ON_ERROR:
858 gBS->RestoreTPL (OldTpl);
859 return Status;
860 }
861
862
863 /**
864 Extends the lease time by sending a request packet.
865
866 The RenewRebind() function is used to manually extend the lease time when the
867 EFI DHCPv4 Protocol driver is in the Dhcp4Bound state and the lease time has
868 not expired yet. This function will send a request packet to the previously
869 found server (or to any server when RebindRequest is TRUE) and transfer the
870 state into the Dhcp4Renewing state (or Dhcp4Rebinding when RebindingRequest is
871 TRUE). When a response is received, the state is returned to Dhcp4Bound.
872 If no response is received before the try count is exceeded (the RequestTryCount
873 field that is specified in EFI_DHCP4_CONFIG_DATA) but before the lease time that
874 was issued by the previous server expires, the driver will return to the Dhcp4Bound
875 state and the previous configuration is restored. The outgoing and incoming packets
876 can be captured by the EFI_DHCP4_CALLBACK function.
877
878 @param This Pointer to the EFI_DHCP4_PROTOCOL instance.
879 @param RebindRequest If TRUE, this function broadcasts the request packets and enters
880 the Dhcp4Rebinding state. Otherwise, it sends a unicast
881 request packet and enters the Dhcp4Renewing state.
882 @param CompletionEvent If not NULL, this event is signaled when the renew/rebind phase
883 completes or some error occurs.
884 EFI_DHCP4_PROTOCOL.GetModeData() can be called to
885 check the completion status. If NULL,
886 EFI_DHCP4_PROTOCOL.RenewRebind() will busy-wait
887 until the DHCP process finishes.
888
889 @retval EFI_SUCCESS The EFI DHCPv4 Protocol driver is now in the
890 Dhcp4Renewing state or is back to the Dhcp4Bound state.
891 @retval EFI_NOT_STARTED The EFI DHCPv4 Protocol driver is in the Dhcp4Stopped
892 state. EFI_DHCP4_PROTOCOL.Configure() needs to
893 be called.
894 @retval EFI_INVALID_PARAMETER This is NULL.
895 @retval EFI_TIMEOUT There was no response from the server when the try count was
896 exceeded.
897 @retval EFI_ACCESS_DENIED The driver is not in the Dhcp4Bound state.
898 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
899
900 **/
901 EFI_STATUS
902 EFIAPI
903 EfiDhcp4RenewRebind (
904 IN EFI_DHCP4_PROTOCOL *This,
905 IN BOOLEAN RebindRequest,
906 IN EFI_EVENT CompletionEvent OPTIONAL
907 )
908 {
909 DHCP_PROTOCOL *Instance;
910 DHCP_SERVICE *DhcpSb;
911 EFI_STATUS Status;
912 EFI_TPL OldTpl;
913
914 //
915 // First validate the parameters
916 //
917 if (This == NULL) {
918 return EFI_INVALID_PARAMETER;
919 }
920
921 Instance = DHCP_INSTANCE_FROM_THIS (This);
922
923 if (Instance->Signature != DHCP_PROTOCOL_SIGNATURE) {
924 return EFI_INVALID_PARAMETER;
925 }
926
927 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
928 DhcpSb = Instance->Service;
929
930 if (DhcpSb->DhcpState == Dhcp4Stopped) {
931 Status = EFI_NOT_STARTED;
932 goto ON_ERROR;
933 }
934
935 if (DhcpSb->DhcpState != Dhcp4Bound) {
936 Status = EFI_ACCESS_DENIED;
937 goto ON_ERROR;
938 }
939
940 if (DHCP_IS_BOOTP (DhcpSb->Para)) {
941 return EFI_SUCCESS;
942 }
943
944 //
945 // Transit the states then send a extra DHCP request
946 //
947 if (!RebindRequest) {
948 DhcpSetState (DhcpSb, Dhcp4Renewing, FALSE);
949 } else {
950 DhcpSetState (DhcpSb, Dhcp4Rebinding, FALSE);
951 }
952
953 Status = DhcpSendMessage (
954 DhcpSb,
955 DhcpSb->Selected,
956 DhcpSb->Para,
957 DHCP_MSG_REQUEST,
958 (UINT8 *) "Extra renew/rebind by the application"
959 );
960
961 if (EFI_ERROR (Status)) {
962 DhcpSetState (DhcpSb, Dhcp4Bound, FALSE);
963 goto ON_ERROR;
964 }
965
966 DhcpSb->ExtraRefresh = TRUE;
967 DhcpSb->IoStatus = EFI_ALREADY_STARTED;
968 Instance->RenewRebindEvent = CompletionEvent;
969
970 gBS->RestoreTPL (OldTpl);
971
972 if (CompletionEvent == NULL) {
973 while (DhcpSb->IoStatus == EFI_ALREADY_STARTED) {
974 DhcpSb->UdpIo->Udp->Poll (DhcpSb->UdpIo->Udp);
975 }
976
977 return DhcpSb->IoStatus;
978 }
979
980 return EFI_SUCCESS;
981
982 ON_ERROR:
983 gBS->RestoreTPL (OldTpl);
984 return Status;
985 }
986
987
988 /**
989 Releases the current address configuration.
990
991 The Release() function releases the current configured IP address by doing either
992 of the following:
993 * Sending a DHCPRELEASE packet when the EFI DHCPv4 Protocol driver is in the
994 Dhcp4Bound state
995 * Setting the previously assigned IP address that was provided with the
996 EFI_DHCP4_PROTOCOL.Configure() function to 0.0.0.0 when the driver is in
997 Dhcp4InitReboot state
998 After a successful call to this function, the EFI DHCPv4 Protocol driver returns
999 to the Dhcp4Init state and any subsequent incoming packets will be discarded silently.
1000
1001 @param This Pointer to the EFI_DHCP4_PROTOCOL instance.
1002
1003 @retval EFI_SUCCESS The EFI DHCPv4 Protocol driver is now in the Dhcp4Init phase.
1004 @retval EFI_INVALID_PARAMETER This is NULL.
1005 @retval EFI_ACCESS_DENIED The EFI DHCPv4 Protocol driver is not Dhcp4InitReboot state.
1006 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
1007
1008 **/
1009 EFI_STATUS
1010 EFIAPI
1011 EfiDhcp4Release (
1012 IN EFI_DHCP4_PROTOCOL *This
1013 )
1014 {
1015 DHCP_PROTOCOL *Instance;
1016 DHCP_SERVICE *DhcpSb;
1017 EFI_STATUS Status;
1018 EFI_TPL OldTpl;
1019
1020 //
1021 // First validate the parameters
1022 //
1023 if (This == NULL) {
1024 return EFI_INVALID_PARAMETER;
1025 }
1026
1027 Instance = DHCP_INSTANCE_FROM_THIS (This);
1028
1029 if (Instance->Signature != DHCP_PROTOCOL_SIGNATURE) {
1030 return EFI_INVALID_PARAMETER;
1031 }
1032
1033 Status = EFI_SUCCESS;
1034 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1035 DhcpSb = Instance->Service;
1036
1037 if ((DhcpSb->DhcpState != Dhcp4InitReboot) && (DhcpSb->DhcpState != Dhcp4Bound)) {
1038 Status = EFI_ACCESS_DENIED;
1039 goto ON_EXIT;
1040 }
1041
1042 if (!DHCP_IS_BOOTP (DhcpSb->Para) && (DhcpSb->DhcpState == Dhcp4Bound)) {
1043 Status = DhcpSendMessage (
1044 DhcpSb,
1045 DhcpSb->Selected,
1046 DhcpSb->Para,
1047 DHCP_MSG_RELEASE,
1048 NULL
1049 );
1050
1051 if (EFI_ERROR (Status)) {
1052 Status = EFI_DEVICE_ERROR;
1053 goto ON_EXIT;
1054 }
1055 }
1056
1057 DhcpCleanLease (DhcpSb);
1058
1059 ON_EXIT:
1060 gBS->RestoreTPL (OldTpl);
1061 return Status;
1062 }
1063
1064
1065 /**
1066 Stops the current address configuration.
1067
1068 The Stop() function is used to stop the DHCP configuration process. After this
1069 function is called successfully, the EFI DHCPv4 Protocol driver is transferred
1070 into the Dhcp4Stopped state. EFI_DHCP4_PROTOCOL.Configure() needs to be called
1071 before DHCP configuration process can be started again. This function can be
1072 called when the EFI DHCPv4 Protocol driver is in any state.
1073
1074 @param This Pointer to the EFI_DHCP4_PROTOCOL instance.
1075
1076 @retval EFI_SUCCESS The EFI DHCPv4 Protocol driver is now in the Dhcp4Stopped phase.
1077 @retval EFI_INVALID_PARAMETER This is NULL.
1078
1079 **/
1080 EFI_STATUS
1081 EFIAPI
1082 EfiDhcp4Stop (
1083 IN EFI_DHCP4_PROTOCOL *This
1084 )
1085 {
1086 DHCP_PROTOCOL *Instance;
1087 DHCP_SERVICE *DhcpSb;
1088 EFI_TPL OldTpl;
1089
1090 //
1091 // First validate the parameters
1092 //
1093 if (This == NULL) {
1094 return EFI_INVALID_PARAMETER;
1095 }
1096
1097 Instance = DHCP_INSTANCE_FROM_THIS (This);
1098
1099 if (Instance->Signature != DHCP_PROTOCOL_SIGNATURE) {
1100 return EFI_INVALID_PARAMETER;
1101 }
1102
1103 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1104 DhcpSb = Instance->Service;
1105
1106 DhcpCleanLease (DhcpSb);
1107
1108 DhcpSb->DhcpState = Dhcp4Stopped;
1109 DhcpSb->ServiceState = DHCP_UNCONFIGED;
1110
1111 gBS->RestoreTPL (OldTpl);
1112 return EFI_SUCCESS;
1113 }
1114
1115
1116 /**
1117 Builds a DHCP packet, given the options to be appended or deleted or replaced.
1118
1119 The Build() function is used to assemble a new packet from the original packet
1120 by replacing or deleting existing options or appending new options. This function
1121 does not change any state of the EFI DHCPv4 Protocol driver and can be used at
1122 any time.
1123
1124 @param This Pointer to the EFI_DHCP4_PROTOCOL instance.
1125 @param SeedPacket Initial packet to be used as a base for building new packet.
1126 @param DeleteCount Number of opcodes in the DeleteList.
1127 @param DeleteList List of opcodes to be deleted from the seed packet.
1128 Ignored if DeleteCount is zero.
1129 @param AppendCount Number of entries in the OptionList.
1130 @param AppendList Pointer to a DHCP option list to be appended to SeedPacket.
1131 If SeedPacket also contains options in this list, they are
1132 replaced by new options (except pad option). Ignored if
1133 AppendCount is zero. Type EFI_DHCP4_PACKET_OPTION
1134 @param NewPacket Pointer to storage for the pointer to the new allocated packet.
1135 Use the EFI Boot Service FreePool() on the resulting pointer
1136 when done with the packet.
1137
1138 @retval EFI_SUCCESS The new packet was built.
1139 @retval EFI_OUT_OF_RESOURCES Storage for the new packet could not be allocated.
1140 @retval EFI_INVALID_PARAMETER Some parameter is NULL.
1141
1142 **/
1143 EFI_STATUS
1144 EFIAPI
1145 EfiDhcp4Build (
1146 IN EFI_DHCP4_PROTOCOL *This,
1147 IN EFI_DHCP4_PACKET *SeedPacket,
1148 IN UINT32 DeleteCount,
1149 IN UINT8 *DeleteList OPTIONAL,
1150 IN UINT32 AppendCount,
1151 IN EFI_DHCP4_PACKET_OPTION *AppendList[] OPTIONAL,
1152 OUT EFI_DHCP4_PACKET **NewPacket
1153 )
1154 {
1155 //
1156 // First validate the parameters
1157 //
1158 if ((This == NULL) || (NewPacket == NULL)) {
1159 return EFI_INVALID_PARAMETER;
1160 }
1161
1162 if ((SeedPacket == NULL) || (SeedPacket->Dhcp4.Magik != DHCP_OPTION_MAGIC) ||
1163 EFI_ERROR (DhcpValidateOptions (SeedPacket, NULL))) {
1164
1165 return EFI_INVALID_PARAMETER;
1166 }
1167
1168 if (((DeleteCount == 0) && (AppendCount == 0)) ||
1169 ((DeleteCount != 0) && (DeleteList == NULL)) ||
1170 ((AppendCount != 0) && (AppendList == NULL))) {
1171
1172 return EFI_INVALID_PARAMETER;
1173 }
1174
1175 return DhcpBuild (
1176 SeedPacket,
1177 DeleteCount,
1178 DeleteList,
1179 AppendCount,
1180 AppendList,
1181 NewPacket
1182 );
1183 }
1184
1185 /**
1186 Callback by UdpIoCreatePort() when creating UdpIo for this Dhcp4 instance.
1187
1188 @param UdpIo The UdpIo being created.
1189 @param Context Dhcp4 instance.
1190
1191 @retval EFI_SUCCESS UdpIo is configured successfully.
1192 @retval other Other error occurs.
1193 **/
1194 EFI_STATUS
1195 Dhcp4InstanceConfigUdpIo (
1196 IN UDP_IO_PORT *UdpIo,
1197 IN VOID *Context
1198 )
1199 {
1200 DHCP_PROTOCOL *Instance;
1201 DHCP_SERVICE *DhcpSb;
1202 EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN *Token;
1203 EFI_UDP4_CONFIG_DATA UdpConfigData;
1204 IP4_ADDR Ip;
1205
1206 Instance = (DHCP_PROTOCOL *) Context;
1207 DhcpSb = Instance->Service;
1208 Token = Instance->Token;
1209
1210 ZeroMem (&UdpConfigData, sizeof (EFI_UDP4_CONFIG_DATA));
1211
1212 UdpConfigData.AcceptBroadcast = TRUE;
1213 UdpConfigData.AllowDuplicatePort = TRUE;
1214 UdpConfigData.TimeToLive = 64;
1215 UdpConfigData.DoNotFragment = TRUE;
1216
1217 Ip = HTONL (DhcpSb->ClientAddr);
1218 CopyMem (&UdpConfigData.StationAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));
1219
1220 Ip = HTONL (DhcpSb->Netmask);
1221 CopyMem (&UdpConfigData.SubnetMask, &Ip, sizeof (EFI_IPv4_ADDRESS));
1222
1223 if ((Token->ListenPointCount == 0) || (Token->ListenPoints[0].ListenPort == 0)) {
1224 UdpConfigData.StationPort = DHCP_CLIENT_PORT;
1225 } else {
1226 UdpConfigData.StationPort = Token->ListenPoints[0].ListenPort;
1227 }
1228
1229 return UdpIo->Udp->Configure (UdpIo->Udp, &UdpConfigData);
1230 }
1231
1232 /**
1233 Create UdpIo for this Dhcp4 instance.
1234
1235 @param Instance The Dhcp4 instance.
1236
1237 @retval EFI_SUCCESS UdpIo is created successfully.
1238 @retval EFI_OUT_OF_RESOURCES Fails to create UdpIo because of limited
1239 resources or configuration failure.
1240 **/
1241 EFI_STATUS
1242 Dhcp4InstanceCreateUdpIo (
1243 IN OUT DHCP_PROTOCOL *Instance
1244 )
1245 {
1246 DHCP_SERVICE *DhcpSb;
1247
1248 ASSERT (Instance->Token != NULL);
1249
1250 DhcpSb = Instance->Service;
1251 Instance->UdpIo = UdpIoCreatePort (DhcpSb->Controller, DhcpSb->Image, Dhcp4InstanceConfigUdpIo, Instance);
1252 if (Instance->UdpIo == NULL) {
1253 return EFI_OUT_OF_RESOURCES;
1254 } else {
1255 return EFI_SUCCESS;
1256 }
1257 }
1258
1259 /**
1260 Callback of Dhcp packet. Does nothing.
1261
1262 @param Arg The context.
1263
1264 @return None.
1265 **/
1266 VOID
1267 DhcpDummyExtFree (
1268 IN VOID *Arg
1269 )
1270 {
1271 }
1272
1273 /**
1274 Callback of UdpIoRecvDatagram() that handles a Dhcp4 packet.
1275
1276 Only BOOTP responses will be handled that correspond to the Xid of the request
1277 sent out. The packet will be queued to the response queue.
1278
1279 @param UdpPacket The Dhcp4 packet.
1280 @param Points Udp4 address pair.
1281 @param IoStatus Status of the input.
1282 @param Context Extra info for the input.
1283
1284 @return None.
1285
1286 **/
1287 VOID
1288 PxeDhcpInput (
1289 NET_BUF *UdpPacket,
1290 UDP_POINTS *Points,
1291 EFI_STATUS IoStatus,
1292 VOID *Context
1293 )
1294 {
1295 DHCP_PROTOCOL *Instance;
1296 DHCP_SERVICE *DhcpSb;
1297 EFI_DHCP4_HEADER *Head;
1298 NET_BUF *Wrap;
1299 EFI_DHCP4_PACKET *Packet;
1300 EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN *Token;
1301 UINT32 Len;
1302 EFI_STATUS Status;
1303
1304 Wrap = NULL;
1305 Instance = (DHCP_PROTOCOL *) Context;
1306 Token = Instance->Token;
1307 DhcpSb = Instance->Service;
1308
1309 //
1310 // Don't restart receive if error occurs or DHCP is destroyed.
1311 //
1312 if (EFI_ERROR (IoStatus)) {
1313 return ;
1314 }
1315
1316 ASSERT (UdpPacket != NULL);
1317
1318 //
1319 // Validate the packet received
1320 //
1321 if (UdpPacket->TotalSize < sizeof (EFI_DHCP4_HEADER)) {
1322 goto RESTART;
1323 }
1324
1325 //
1326 // Copy the DHCP message to a continuous memory block, make the buffer size
1327 // of the EFI_DHCP4_PACKET a multiple of 4-byte.
1328 //
1329 Len = NET_ROUNDUP (sizeof (EFI_DHCP4_PACKET) + UdpPacket->TotalSize - sizeof (EFI_DHCP4_HEADER), 4);
1330 Wrap = NetbufAlloc (Len);
1331
1332 if (Wrap == NULL) {
1333 goto RESTART;
1334 }
1335
1336 Packet = (EFI_DHCP4_PACKET *) NetbufAllocSpace (Wrap, Len, NET_BUF_TAIL);
1337 Packet->Size = Len;
1338 Head = &Packet->Dhcp4.Header;
1339 Packet->Length = NetbufCopy (UdpPacket, 0, UdpPacket->TotalSize, (UINT8 *) Head);
1340
1341 if (Packet->Length != UdpPacket->TotalSize) {
1342 goto RESTART;
1343 }
1344
1345 //
1346 // Is this packet the answer to our packet?
1347 //
1348 if ((Head->OpCode != BOOTP_REPLY) ||
1349 (Head->Xid != Token->Packet->Dhcp4.Header.Xid) ||
1350 (CompareMem (DhcpSb->ClientAddressSendOut, Head->ClientHwAddr, Head->HwAddrLen) != 0)) {
1351 goto RESTART;
1352 }
1353
1354 //
1355 // Validate the options and retrieve the interested options
1356 //
1357 if ((Packet->Length > sizeof (EFI_DHCP4_HEADER) + sizeof (UINT32)) &&
1358 (Packet->Dhcp4.Magik == DHCP_OPTION_MAGIC) &&
1359 EFI_ERROR (DhcpValidateOptions (Packet, NULL))) {
1360
1361 goto RESTART;
1362 }
1363
1364 //
1365 // Keep this packet in the ResponseQueue.
1366 //
1367 NET_GET_REF (Wrap);
1368 NetbufQueAppend (&Instance->ResponseQueue, Wrap);
1369
1370 RESTART:
1371
1372 NetbufFree (UdpPacket);
1373
1374 if (Wrap != NULL) {
1375 NetbufFree (Wrap);
1376 }
1377
1378 Status = UdpIoRecvDatagram (Instance->UdpIo, PxeDhcpInput, Instance, 0);
1379 if (EFI_ERROR (Status)) {
1380 PxeDhcpDone (Instance);
1381 }
1382 }
1383
1384 /**
1385 Complete a Dhcp4 transaction and signal the upper layer.
1386
1387 @param Instance Dhcp4 instance.
1388
1389 @return None.
1390
1391 **/
1392 VOID
1393 PxeDhcpDone (
1394 IN DHCP_PROTOCOL *Instance
1395 )
1396 {
1397 EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN *Token;
1398
1399 Token = Instance->Token;
1400
1401 Token->ResponseCount = Instance->ResponseQueue.BufNum;
1402 if (Token->ResponseCount != 0) {
1403 Token->ResponseList = (EFI_DHCP4_PACKET *) AllocatePool (Instance->ResponseQueue.BufSize);
1404 if (Token->ResponseList == NULL) {
1405 Token->Status = EFI_OUT_OF_RESOURCES;
1406 goto SIGNAL_USER;
1407 }
1408
1409 //
1410 // Copy the received DHCP responses.
1411 //
1412 NetbufQueCopy (&Instance->ResponseQueue, 0, Instance->ResponseQueue.BufSize, (UINT8 *) Token->ResponseList);
1413 Token->Status = EFI_SUCCESS;
1414 } else {
1415 Token->ResponseList = NULL;
1416 Token->Status = EFI_TIMEOUT;
1417 }
1418
1419 SIGNAL_USER:
1420 //
1421 // Clean up the resources dedicated for this transmit receive transaction.
1422 //
1423 NetbufQueFlush (&Instance->ResponseQueue);
1424 UdpIoCleanPort (Instance->UdpIo);
1425 UdpIoFreePort (Instance->UdpIo);
1426 Instance->UdpIo = NULL;
1427 Instance->Token = NULL;
1428
1429 if (Token->CompletionEvent != NULL) {
1430 gBS->SignalEvent (Token->CompletionEvent);
1431 }
1432 }
1433
1434
1435 /**
1436 Transmits a DHCP formatted packet and optionally waits for responses.
1437
1438 The TransmitReceive() function is used to transmit a DHCP packet and optionally
1439 wait for the response from servers. This function does not change the state of
1440 the EFI DHCPv4 Protocol driver and thus can be used at any time.
1441
1442 @param This Pointer to the EFI_DHCP4_PROTOCOL instance.
1443 @param Token Pointer to the EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN structure.
1444
1445 @retval EFI_SUCCESS The packet was successfully queued for transmission.
1446 @retval EFI_INVALID_PARAMETER Some parameter is NULL.
1447 @retval EFI_NOT_READY The previous call to this function has not finished yet. Try to call
1448 this function after collection process completes.
1449 @retval EFI_NO_MAPPING The default station address is not available yet.
1450 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1451 @retval Others Some other unexpected error occurred.
1452
1453 **/
1454 EFI_STATUS
1455 EFIAPI
1456 EfiDhcp4TransmitReceive (
1457 IN EFI_DHCP4_PROTOCOL *This,
1458 IN EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN *Token
1459 )
1460 {
1461 DHCP_PROTOCOL *Instance;
1462 EFI_TPL OldTpl;
1463 EFI_STATUS Status;
1464 NET_FRAGMENT Frag;
1465 NET_BUF *Wrap;
1466 UDP_POINTS EndPoint;
1467 IP4_ADDR Ip;
1468 DHCP_SERVICE *DhcpSb;
1469 IP4_ADDR Gateway;
1470 IP4_ADDR SubnetMask;
1471
1472 if ((This == NULL) || (Token == NULL) || (Token->Packet == NULL)) {
1473 return EFI_INVALID_PARAMETER;
1474 }
1475
1476 Instance = DHCP_INSTANCE_FROM_THIS (This);
1477 DhcpSb = Instance->Service;
1478
1479 if (Instance->Token != NULL) {
1480 //
1481 // The previous call to TransmitReceive is not finished.
1482 //
1483 return EFI_NOT_READY;
1484 }
1485
1486 if ((Token->Packet->Dhcp4.Magik != DHCP_OPTION_MAGIC) ||
1487 (NTOHL (Token->Packet->Dhcp4.Header.Xid) == Instance->Service->Xid) ||
1488 (Token->TimeoutValue == 0) ||
1489 ((Token->ListenPointCount != 0) && (Token->ListenPoints == NULL)) ||
1490 EFI_ERROR (DhcpValidateOptions (Token->Packet, NULL)) ||
1491 EFI_IP4_EQUAL (&Token->RemoteAddress, &mZeroIp4Addr)
1492 ) {
1493 //
1494 // The DHCP packet isn't well-formed, the Transaction ID is already used,
1495 // the timeout value is zero, the ListenPoint is invalid, or the
1496 // RemoteAddress is zero.
1497 //
1498 return EFI_INVALID_PARAMETER;
1499 }
1500
1501 if (DhcpSb->ClientAddr == 0) {
1502
1503 return EFI_NO_MAPPING;
1504 }
1505
1506 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1507
1508 //
1509 // Save the token and the timeout value.
1510 //
1511 Instance->Token = Token;
1512 Instance->Timeout = Token->TimeoutValue;
1513
1514 //
1515 // Create a UDP IO for this transmit receive transaction.
1516 //
1517 Status = Dhcp4InstanceCreateUdpIo (Instance);
1518 if (EFI_ERROR (Status)) {
1519 goto ON_ERROR;
1520 }
1521
1522 //
1523 // Save the Client Address is sent out
1524 //
1525 CopyMem (
1526 &DhcpSb->ClientAddressSendOut[0],
1527 &Token->Packet->Dhcp4.Header.ClientHwAddr[0],
1528 Token->Packet->Dhcp4.Header.HwAddrLen
1529 );
1530
1531 //
1532 // Wrap the DHCP packet into a net buffer.
1533 //
1534 Frag.Bulk = (UINT8 *) &Token->Packet->Dhcp4;
1535 Frag.Len = Token->Packet->Length;
1536 Wrap = NetbufFromExt (&Frag, 1, 0, 0, DhcpDummyExtFree, NULL);
1537 if (Wrap == NULL) {
1538 Status = EFI_OUT_OF_RESOURCES;
1539 goto ON_ERROR;
1540 }
1541
1542 //
1543 // Set the local address and local port.
1544 //
1545 EndPoint.LocalAddr = 0;
1546 EndPoint.LocalPort = 0;
1547
1548 //
1549 // Set the destination address and destination port.
1550 //
1551 CopyMem (&Ip, &Token->RemoteAddress, sizeof (EFI_IPv4_ADDRESS));
1552 EndPoint.RemoteAddr = NTOHL (Ip);
1553
1554 if (Token->RemotePort == 0) {
1555 EndPoint.RemotePort = DHCP_SERVER_PORT;
1556 } else {
1557 EndPoint.RemotePort = Token->RemotePort;
1558 }
1559
1560 //
1561 // Get the gateway.
1562 //
1563 SubnetMask = DhcpSb->Netmask;
1564 Gateway = 0;
1565 if (!IP4_NET_EQUAL (DhcpSb->ClientAddr, EndPoint.RemoteAddr, SubnetMask)) {
1566 CopyMem (&Gateway, &Token->GatewayAddress, sizeof (EFI_IPv4_ADDRESS));
1567 Gateway = NTOHL (Gateway);
1568 }
1569
1570 //
1571 // Transmit the DHCP packet.
1572 //
1573 Status = UdpIoSendDatagram (Instance->UdpIo, Wrap, &EndPoint, Gateway, DhcpOnPacketSent, NULL);
1574 if (EFI_ERROR (Status)) {
1575 NetbufFree (Wrap);
1576 goto ON_ERROR;
1577 }
1578
1579 //
1580 // Start to receive the DHCP response.
1581 //
1582 Status = UdpIoRecvDatagram (Instance->UdpIo, PxeDhcpInput, Instance, 0);
1583 if (EFI_ERROR (Status)) {
1584 goto ON_ERROR;
1585 }
1586
1587 ON_ERROR:
1588
1589 if (EFI_ERROR (Status) && (Instance->UdpIo != NULL)) {
1590 UdpIoCleanPort (Instance->UdpIo);
1591 UdpIoFreePort (Instance->UdpIo);
1592 Instance->UdpIo = NULL;
1593 Instance->Token = NULL;
1594 }
1595
1596 gBS->RestoreTPL (OldTpl);
1597
1598 if (!EFI_ERROR (Status) && (Token->CompletionEvent == NULL)) {
1599 //
1600 // Keep polling until timeout if no error happens and the CompletionEvent
1601 // is NULL.
1602 //
1603 while (Instance->Timeout != 0) {
1604 Instance->UdpIo->Udp->Poll (Instance->UdpIo->Udp);
1605 }
1606 }
1607
1608 return Status;
1609 }
1610
1611
1612 /**
1613 Callback function for DhcpIterateOptions. This callback sets the
1614 EFI_DHCP4_PACKET_OPTION array in the DHCP_PARSE_CONTEXT to point
1615 the individual DHCP option in the packet.
1616
1617 @param Tag The DHCP option type
1618 @param Len Length of the DHCP option data
1619 @param Data The DHCP option data
1620 @param Context The context, to pass several parameters in.
1621
1622 @retval EFI_SUCCESS It always returns EFI_SUCCESS
1623
1624 **/
1625 EFI_STATUS
1626 Dhcp4ParseCheckOption (
1627 IN UINT8 Tag,
1628 IN UINT8 Len,
1629 IN UINT8 *Data,
1630 IN VOID *Context
1631 )
1632 {
1633 DHCP_PARSE_CONTEXT *Parse;
1634
1635 Parse = (DHCP_PARSE_CONTEXT *) Context;
1636 Parse->Index++;
1637
1638 if (Parse->Index <= Parse->OptionCount) {
1639 //
1640 // Use _CR to get the memory position of EFI_DHCP4_PACKET_OPTION for
1641 // the EFI_DHCP4_PACKET_OPTION->Data because DhcpIterateOptions only
1642 // pass in the point to option data.
1643 //
1644 Parse->Option[Parse->Index - 1] = _CR (Data, EFI_DHCP4_PACKET_OPTION, Data);
1645 }
1646
1647 return EFI_SUCCESS;
1648 }
1649
1650
1651 /**
1652 Parses the packed DHCP option data.
1653
1654 The Parse() function is used to retrieve the option list from a DHCP packet.
1655 If *OptionCount isn’t zero, and there is enough space for all the DHCP options
1656 in the Packet, each element of PacketOptionList is set to point to somewhere in
1657 the Packet->Dhcp4.Option where a new DHCP option begins. If RFC3396 is supported,
1658 the caller should reassemble the parsed DHCP options to get the finial result.
1659 If *OptionCount is zero or there isn’t enough space for all of them, the number
1660 of DHCP options in the Packet is returned in OptionCount.
1661
1662 @param This Pointer to the EFI_DHCP4_PROTOCOL instance.
1663 @param Packet Pointer to packet to be parsed.
1664 @param OptionCount On input, the number of entries in the PacketOptionList.
1665 On output, the number of entries that were written into the
1666 PacketOptionList.
1667 @param PacketOptionList List of packet option entries to be filled in. End option or pad
1668 options are not included.
1669
1670 @retval EFI_SUCCESS The packet was successfully parsed.
1671 @retval EFI_INVALID_PARAMETER Some parameter is NULL.
1672 @retval EFI_BUFFER_TOO_SMALL One or more of the following conditions is TRUE:
1673 1) *OptionCount is smaller than the number of options that
1674 were found in the Packet.
1675 2) PacketOptionList is NULL.
1676
1677 **/
1678 EFI_STATUS
1679 EFIAPI
1680 EfiDhcp4Parse (
1681 IN EFI_DHCP4_PROTOCOL *This,
1682 IN EFI_DHCP4_PACKET *Packet,
1683 IN OUT UINT32 *OptionCount,
1684 OUT EFI_DHCP4_PACKET_OPTION *PacketOptionList[] OPTIONAL
1685 )
1686 {
1687 DHCP_PARSE_CONTEXT Context;
1688 EFI_STATUS Status;
1689
1690 //
1691 // First validate the parameters
1692 //
1693 if ((This == NULL) || (Packet == NULL) || (OptionCount == NULL)) {
1694 return EFI_INVALID_PARAMETER;
1695 }
1696
1697 if ((Packet->Size < Packet->Length + 2 * sizeof (UINT32)) ||
1698 (Packet->Dhcp4.Magik != DHCP_OPTION_MAGIC) ||
1699 EFI_ERROR (DhcpValidateOptions (Packet, NULL))) {
1700
1701 return EFI_INVALID_PARAMETER;
1702 }
1703
1704 if ((*OptionCount != 0) && (PacketOptionList == NULL)) {
1705 return EFI_BUFFER_TOO_SMALL;
1706 }
1707
1708 ZeroMem (PacketOptionList, *OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *));
1709
1710 Context.Option = PacketOptionList;
1711 Context.OptionCount = *OptionCount;
1712 Context.Index = 0;
1713
1714 Status = DhcpIterateOptions (Packet, Dhcp4ParseCheckOption, &Context);
1715
1716 if (EFI_ERROR (Status)) {
1717 return Status;
1718 }
1719
1720 *OptionCount = Context.Index;
1721
1722 if (Context.Index > Context.OptionCount) {
1723 return EFI_BUFFER_TOO_SMALL;
1724 }
1725
1726 return EFI_SUCCESS;
1727 }