#include "stdhead.h"
#include "reply.h"
#include "lib.h"

struct OPTIONS * copy_ia_option (struct DHCP_MESSAGE * request_message, struct OPTIONS * opt_ptr)
{
    struct IA *ia_ptr;
    struct OPTIONS *options_ptr;
    
    options_ptr = get_options_ptr (request_message, OPTION_IA);
    if (!options_ptr)
	return NULL;
	
    opt_ptr -> u_opt_code.opt_code = OPTION_IA;
    opt_ptr -> u_opt_len.opt_len = options_ptr -> u_opt_len.opt_len;

    ia_ptr = opt_ptr -> opt_data = (struct IA *) malloc (sizeof (struct IA));
    ia_ptr -> u_iaid.iaid = ((struct IA *) options_ptr -> opt_data) -> u_iaid.iaid;
    ia_ptr -> u_t1.t1 = ((struct IA *) options_ptr -> opt_data) -> u_t1.t1;
    ia_ptr -> u_t2.t2 = ((struct IA *) options_ptr -> opt_data) -> u_t2.t2;
    ia_ptr -> status = Success;

    opt_ptr = ia_ptr -> opt = (struct OPTIONS *) malloc (sizeof (struct OPTIONS));
    return opt_ptr;
}

void copy_iaaddr_option (struct DHCP_MESSAGE * request_message, struct OPTIONS * opt_ptr)
{
    int i;
    struct OPTIONS *options_ptr;
    struct IA_ADDRESS *ia_addr_ptr;
    
    options_ptr = get_options_ptr (request_message, OPTION_IAADDR);
    if (!options_ptr)
	return;
	
    opt_ptr -> u_opt_code.opt_code = OPTION_IAADDR;
    opt_ptr -> u_opt_len.opt_len = options_ptr -> u_opt_len.opt_len;

    ia_addr_ptr = opt_ptr -> opt_data = (struct IA_ADDRESS *) malloc (sizeof (struct IA_ADDRESS));
    ia_addr_ptr -> t_bit = 0;
    ia_addr_ptr -> addr_status = Success;
    ia_addr_ptr -> prefix_length = ((struct IA_ADDRESS *) options_ptr -> opt_data) -> prefix_length;
    for (i = 0; i < 16; i++)
	ia_addr_ptr -> addr[i] = ((struct IA_ADDRESS *) options_ptr -> opt_data) -> addr[i];
    ia_addr_ptr -> u_pref_lifetime.pref_lifetime = ((struct IA_ADDRESS *) options_ptr -> opt_data) -> u_pref_lifetime.pref_lifetime;
    ia_addr_ptr -> u_valid_lifetime.valid_lifetime = ((struct IA_ADDRESS *) options_ptr -> opt_data) -> u_valid_lifetime.valid_lifetime;
    ia_addr_ptr -> ia_addr_opt = 0;
    ia_addr_ptr -> opt = 0;
}

struct DHCP_MESSAGE * create_reply_message (struct DHCP_MESSAGE *message)
{
    struct DHCP_MESSAGE * dhcp_message_ptr = malloc (sizeof (struct DHCP_MESSAGE));
    struct OPTIONS * opt_ptr;

    // MESSAGE TYPE
    dhcp_message_ptr->u_msg_type.msg_type = REPLY;

    // Copy TRANSACTION ID from message
    dhcp_message_ptr -> u_trans_id.trans_id = message -> u_trans_id.trans_id;

    // ASSIGN MEMORY FOR OPTIONS
    opt_ptr = dhcp_message_ptr->opt = (struct OPTIONS *) malloc (sizeof (struct OPTIONS));

    // copy CLIENT ID OPTION CODE from solicit message
    opt_ptr = copy_client_id (message, opt_ptr);
    
    // send SERVER Id option
    opt_ptr = send_server_id (opt_ptr);
    
    // copy IA option
    opt_ptr = copy_ia_option (message, opt_ptr);
    
    // copy IAADDR option
    copy_iaaddr_option (message, opt_ptr);
	
    return dhcp_message_ptr;
}

struct DHCP_MESSAGE * create_reply_message_for_decline (struct DHCP_MESSAGE *decline_message)
{
    struct DHCP_MESSAGE * dhcp_message_ptr;
    struct OPTIONS *opt_ptr;
    struct STATUS_CODE *sc_ptr;
    struct DUID *duid_ptr;
    
    // send Success status code option
    dhcp_message_ptr = create_message_with_status_code (decline_message, REPLY, Success, "Decline message accepted");

    // send server ID option
    opt_ptr = (struct OPTIONS *) malloc (sizeof (struct OPTIONS));
    sc_ptr = ((struct STATUS_CODE *) dhcp_message_ptr -> opt -> opt_data);
    sc_ptr -> opt = opt_ptr;
    opt_ptr = send_server_id (opt_ptr);
    duid_ptr = (struct DUID *) sc_ptr -> opt -> opt_data;
    safe_free (duid_ptr -> opt);
    duid_ptr -> opt = 0;
    
    return dhcp_message_ptr;
}

struct DHCP_MESSAGE * create_reply_message_for_release (struct DHCP_MESSAGE *release_message)
{
    struct DHCP_MESSAGE * dhcp_message_ptr;
    struct OPTIONS *opt_ptr;
    struct STATUS_CODE *sc_ptr;
    struct DUID *duid_ptr;
    
    // send Success status code option
    dhcp_message_ptr = create_message_with_status_code (release_message, REPLY, Success, "Release message accepted");

    // send server ID option
    opt_ptr = (struct OPTIONS *) malloc (sizeof (struct OPTIONS));
    sc_ptr = ((struct STATUS_CODE *) dhcp_message_ptr -> opt -> opt_data);
    sc_ptr -> opt = opt_ptr;
    opt_ptr = send_server_id (opt_ptr);
    duid_ptr = (struct DUID *) sc_ptr -> opt -> opt_data;
    safe_free (duid_ptr -> opt);
    duid_ptr -> opt = 0;
    
    
    return dhcp_message_ptr;
}

struct DHCP_MESSAGE * create_dummy_reply_message (struct DHCP_MESSAGE *message)
{
    struct DHCP_MESSAGE * dhcp_message_ptr = (struct DHCP_MESSAGE *) malloc (sizeof (struct DHCP_MESSAGE));
    struct IA *ia_ptr, *ia_src_ptr;
    struct IA_ADDRESS *iaaddr_ptr, *iaaddr_src_ptr;
    struct OPTIONS *opt_ptr, *opt_src_ptr;

    // MESSAGE TYPE
    dhcp_message_ptr->u_msg_type.msg_type = REPLY;

    // Copy TRANSACTION ID from message
    dhcp_message_ptr -> u_trans_id.trans_id = message -> u_trans_id.trans_id;

    // ASSIGN MEMORY FOR OPTIONS
    opt_ptr = dhcp_message_ptr->opt = (struct OPTIONS *) malloc (sizeof (struct OPTIONS));
    
    // send SERVER Id option
    opt_ptr = send_server_id (opt_ptr);
    
    // set IA option with values set to null (except iaid)
    opt_src_ptr = get_options_ptr (message, OPTION_IA);
    ia_src_ptr = (struct IA *) opt_src_ptr -> opt_data;
    
    opt_ptr -> u_opt_code.opt_code = OPTION_IA;
    opt_ptr -> u_opt_len.opt_len = opt_src_ptr -> u_opt_len.opt_len;
    ia_ptr = (struct IA *) malloc (sizeof (struct IA));
    opt_ptr -> opt_data = ia_ptr;
    bzero (ia_ptr, sizeof (struct IA));
    ia_ptr -> u_iaid.iaid = ia_src_ptr -> u_iaid.iaid;
    
    // set IAADDR option with values set to null
    opt_src_ptr = get_options_ptr (message, OPTION_IAADDR);
    iaaddr_src_ptr = (struct IA_ADDRESS *) opt_src_ptr -> opt_data;
    
    opt_ptr = ia_ptr -> opt = (struct OPTIONS *) malloc (sizeof (struct OPTIONS));
    opt_ptr -> u_opt_code.opt_code = OPTION_IAADDR;
    opt_ptr -> u_opt_len.opt_len = opt_src_ptr -> u_opt_len.opt_len;
    iaaddr_ptr = (struct IA_ADDRESS *) malloc (sizeof (struct IA_ADDRESS));
    opt_ptr -> opt_data = iaaddr_ptr;
    bzero (iaaddr_ptr, sizeof (struct IA_ADDRESS));
    
    return dhcp_message_ptr;
}
