git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			247 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			247 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*++
 | |
| 
 | |
| Copyright (c) 2006, Intel Corporation                                                         
 | |
| All rights reserved. This program and the accompanying materials                          
 | |
| are licensed and made available under the terms and conditions of the BSD License         
 | |
| which accompanies this distribution.  The full text of the license may be found at        
 | |
| http://opensource.org/licenses/bsd-license.php                                            
 | |
|                                                                                           
 | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     
 | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             
 | |
| 
 | |
| Module Name:
 | |
|   PxeDhcp4Release.c
 | |
|   
 | |
| Abstract:
 | |
|   Transmit release packet, free allocations and shutdown PxeDhcp4.
 | |
| 
 | |
| --*/
 | |
| 
 | |
| 
 | |
| #include "PxeDhcp4.h"
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| PxeDhcp4Release (
 | |
|   IN EFI_PXE_DHCP4_PROTOCOL *This
 | |
|   )
 | |
| {
 | |
|   PXE_DHCP4_PRIVATE_DATA  *Private;
 | |
|   EFI_IP_ADDRESS          ServerIp;
 | |
|   EFI_IP_ADDRESS          client_ip;
 | |
|   EFI_IP_ADDRESS          gateway_ip;
 | |
|   EFI_IP_ADDRESS          subnet_mask;
 | |
|   EFI_STATUS              efi_status;
 | |
|   DHCP4_OP                *op;
 | |
|   UINT8                   op_list[20];
 | |
| 
 | |
|   //
 | |
|   // Check for invalid parameters.
 | |
|   //
 | |
|   if (This == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
|   //
 | |
|   // Release does nothing if the protocol has never been setup.
 | |
|   //
 | |
|   if (This->Data == NULL) {
 | |
|     return EFI_NOT_STARTED;
 | |
|   }
 | |
|   //
 | |
|   // Fail if we do not have valid instance data.
 | |
|   //
 | |
|   Private = PXE_DHCP4_PRIVATE_DATA_FROM_THIS (This);
 | |
| 
 | |
|   if (Private == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if (Private->PxeBc == NULL) {
 | |
|     return EFI_DEVICE_ERROR;
 | |
|   }
 | |
|   //
 | |
|   // If this is a BOOTP session and there is not a DHCP Ack
 | |
|   // packet, just release storage and return.
 | |
|   //
 | |
|   if (This->Data->IsBootp || !This->Data->IsAck) {
 | |
|     gBS->FreePool (This->Data);
 | |
|     This->Data = NULL;
 | |
| 
 | |
|     if (Private->StopPxeBc) {
 | |
|       Private->PxeBc->Stop (Private->PxeBc);
 | |
|     }
 | |
| 
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
|   //
 | |
|   // Build option list for DHCP Release packet.
 | |
|   // If any errors occur, just release storage and return.
 | |
|   //
 | |
|   //
 | |
|   // Message type is first.
 | |
|   //
 | |
|   op_list[0]  = DHCP4_MESSAGE_TYPE;
 | |
|   op_list[1]  = 1;
 | |
|   op_list[2]  = DHCP4_MESSAGE_TYPE_RELEASE;
 | |
| 
 | |
|   //
 | |
|   // Followed by server identifier.
 | |
|   //
 | |
|   efi_status = find_opt (
 | |
|                 &This->Data->Request,
 | |
|                 DHCP4_SERVER_IDENTIFIER,
 | |
|                 0,
 | |
|                 &op
 | |
|                 );
 | |
| 
 | |
|   if (EFI_ERROR (efi_status)) {
 | |
|     gBS->FreePool (This->Data);
 | |
|     This->Data = NULL;
 | |
| 
 | |
|     if (Private->StopPxeBc) {
 | |
|       Private->PxeBc->Stop (Private->PxeBc);
 | |
|     }
 | |
| 
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   if (op->len != 4) {
 | |
|     gBS->FreePool (This->Data);
 | |
|     This->Data = NULL;
 | |
| 
 | |
|     if (Private->StopPxeBc) {
 | |
|       Private->PxeBc->Stop (Private->PxeBc);
 | |
|     }
 | |
| 
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   CopyMem (&ServerIp, op->data, 4);
 | |
| 
 | |
|   op_list[3]  = DHCP4_SERVER_IDENTIFIER;
 | |
|   op_list[4]  = 4;
 | |
|   CopyMem (&op_list[5], &ServerIp, 4);
 | |
| 
 | |
|   //
 | |
|   // Followed by end.
 | |
|   //
 | |
|   op_list[9] = DHCP4_END;
 | |
| 
 | |
|   //
 | |
|   // We need a subnet mask for IP stack operation.
 | |
|   //
 | |
|   efi_status = find_opt (
 | |
|                 &This->Data->AckNak,
 | |
|                 DHCP4_SUBNET_MASK,
 | |
|                 0,
 | |
|                 &op
 | |
|                 );
 | |
| 
 | |
|   if (EFI_ERROR (efi_status)) {
 | |
|     gBS->FreePool (This->Data);
 | |
|     This->Data = NULL;
 | |
| 
 | |
|     if (Private->StopPxeBc) {
 | |
|       Private->PxeBc->Stop (Private->PxeBc);
 | |
|     }
 | |
| 
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   if (op->len != 4) {
 | |
|     gBS->FreePool (This->Data);
 | |
|     This->Data = NULL;
 | |
| 
 | |
|     if (Private->StopPxeBc) {
 | |
|       Private->PxeBc->Stop (Private->PxeBc);
 | |
|     }
 | |
| 
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   ZeroMem (&subnet_mask, sizeof (EFI_IP_ADDRESS));
 | |
|   CopyMem (&subnet_mask, op->data, 4);
 | |
| 
 | |
|   //
 | |
|   // Gateway IP address may be needed.
 | |
|   //
 | |
|   ZeroMem (&gateway_ip, sizeof (EFI_IP_ADDRESS));
 | |
|   CopyMem (&gateway_ip, &This->Data->AckNak.dhcp4.giaddr, 4);
 | |
| 
 | |
|   //
 | |
|   // Client IP address needed for IP stack operation.
 | |
|   //
 | |
|   ZeroMem (&client_ip, sizeof (EFI_IP_ADDRESS));
 | |
|   CopyMem (&client_ip, &This->Data->AckNak.dhcp4.yiaddr, 4);
 | |
| 
 | |
|   //
 | |
|   // Enable UDP...
 | |
|   //
 | |
|   efi_status = start_udp (Private, &client_ip, &subnet_mask);
 | |
| 
 | |
|   if (EFI_ERROR (efi_status)) {
 | |
|     gBS->FreePool (This->Data);
 | |
|     This->Data = NULL;
 | |
| 
 | |
|     if (Private->StopPxeBc) {
 | |
|       Private->PxeBc->Stop (Private->PxeBc);
 | |
|     }
 | |
| 
 | |
|     return efi_status;
 | |
|   }
 | |
|   //
 | |
|   // Gather information out of DHCP request packet needed for
 | |
|   // DHCP release packet.
 | |
|   //
 | |
|   //
 | |
|   // Setup DHCP Release packet.
 | |
|   //
 | |
|   CopyMem (&This->Data->Request.dhcp4.ciaddr, &client_ip, 4);
 | |
| 
 | |
|   ZeroMem (&This->Data->Request.dhcp4.yiaddr, 12);
 | |
| 
 | |
|   ZeroMem (&This->Data->Request.dhcp4.sname, 64 + 128);
 | |
| 
 | |
|   This->Data->Request.dhcp4.hops  = 0;
 | |
|   This->Data->Request.dhcp4.secs  = 0;
 | |
|   This->Data->Request.dhcp4.flags = 0;
 | |
| 
 | |
|   ZeroMem (
 | |
|     &This->Data->Request.dhcp4.options,
 | |
|     sizeof This->Data->Request.dhcp4.options
 | |
|     );
 | |
| 
 | |
|   CopyMem (&This->Data->Request.dhcp4.options, op_list, 10);
 | |
| 
 | |
|   //
 | |
|   // Transmit DHCP Release packet.
 | |
|   //
 | |
|   tx_udp (
 | |
|     Private,
 | |
|     &ServerIp,
 | |
|     &gateway_ip,
 | |
|     &client_ip,
 | |
|     &This->Data->Request,
 | |
|     DHCP4_MAX_PACKET_SIZE - (DHCP4_UDP_HEADER_SIZE + DHCP4_IP_HEADER_SIZE)
 | |
|     );
 | |
| 
 | |
|   gBS->Stall (1000000); /* 1/10th second */
 | |
| 
 | |
|   //
 | |
|   // Shutdown PXE BaseCode and release local storage.
 | |
|   //
 | |
|   stop_udp (Private);
 | |
| 
 | |
|   gBS->FreePool (This->Data);
 | |
|   This->Data = NULL;
 | |
| 
 | |
|   if (Private->StopPxeBc) {
 | |
|     Private->PxeBc->Stop (Private->PxeBc);
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /* eof - PxeDhcp4Release.c */
 |