1426 lines
53 KiB
C
1426 lines
53 KiB
C
/*
|
|
******************************************************************************
|
|
* INTERPEAK SOURCE FILE
|
|
*
|
|
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipdhcps6_msg.c,v $ $Revision: 1.40.12.2 $
|
|
* $Source: /home/interpeak/CVSRoot/ipdhcps6/src/ipdhcps6_msg.c,v $
|
|
* $Author: svc-cmnet $
|
|
* $State: Exp $ $Locker: $
|
|
*
|
|
* INTERPEAK_COPYRIGHT_STRING
|
|
* Design and implementation by Kenneth Jonsson <kenneth@interpeak.se>
|
|
******************************************************************************
|
|
*/
|
|
|
|
/* Copyright (C) 2007 Wind River Systems */
|
|
|
|
/*
|
|
modification history
|
|
--------------------
|
|
01a,17jul07,ps initial checkin of dhcpv6 authentication key database module
|
|
*/
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 1 DESCRIPTION
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 2 CONFIGURATION
|
|
****************************************************************************
|
|
*/
|
|
|
|
#include "ipdhcps6_config.h"
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 3 INCLUDE FILES
|
|
****************************************************************************
|
|
*/
|
|
|
|
#define IPCOM_USE_CLIB_PROTO
|
|
#include <ipcom_type.h>
|
|
#include <ipcom_cstyle.h>
|
|
#include <ipcom_clib.h>
|
|
#include <ipcom_err.h>
|
|
#include <ipcom_syslog.h>
|
|
#include <ipcom_sysvar.h>
|
|
#include <ipcom_sock.h>
|
|
#include <ipnet_ctrl.h>
|
|
|
|
#include "ipdhcps6.h"
|
|
#include "ipdhcps6_h.h"
|
|
#include "ipdhcps6_msg.h"
|
|
#include "ipdhcps6_host.h"
|
|
#include "ipdhcps6_option.h"
|
|
#include "ipdhcps6_prefix.h"
|
|
#include "ipdhcps6_subnet.h"
|
|
#include "ipdhcps6_authhash.h"
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 4 DEFINES
|
|
****************************************************************************
|
|
*/
|
|
|
|
#define IPDHCPS6_CPY_TRANSACTION_ID(dst, src) \
|
|
do { \
|
|
dst->transaction_id_1 = src->transaction_id_1; \
|
|
dst->transaction_id_2 = src->transaction_id_2; \
|
|
dst->transaction_id_3 = src->transaction_id_3; \
|
|
} while (0)
|
|
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 5 TYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
struct Ipdhcps6_msg_add_opt
|
|
{
|
|
/* The buffer to where the options will be copied */
|
|
Ipdhcps6_option *opts;
|
|
/* The length left in the 'opts' buffer */
|
|
Ip_u16 optslen;
|
|
/* Number of bytes written to the 'opts' buffer */
|
|
Ip_u16 total_written;
|
|
/* Result code of the operation */
|
|
Ip_err err;
|
|
};
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 6 EXTERN PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 7 LOCAL PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 8 DATA
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 9 STATIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipdhcps6_msg_contains_local_server_id
|
|
*===========================================================================
|
|
* Description: Returns IP_TRUE if the options array contains the server ID
|
|
* for this host.
|
|
* Parameters: options - An array of options.
|
|
* optslen - The length of the 'options' buffer.
|
|
* Returns: IP_TRUE if the server ID of this host is included.
|
|
*
|
|
*/
|
|
IP_STATIC Ip_bool
|
|
ipdhcps6_msg_contains_local_server_id(Ipdhcps6_option *options, Ip_u16 optslen)
|
|
{
|
|
Ipdhcps6_option *server_id;
|
|
Ip_u16 server_id_len;
|
|
|
|
server_id = ipdhcps6_option_get_ptr(options, optslen, IPDHCPS6_OPTION_SERVERID);
|
|
|
|
if (server_id == IP_NULL)
|
|
return IP_FALSE;
|
|
|
|
server_id_len = (Ip_u16) (ipdhcps6_get_u16(&server_id->len) + IPDHCPS6_OPTION_HDR_LEN);
|
|
if (server_id_len != ipdhcps6_get_u16(&ipdhcps6->duid->len) + IPDHCPS6_OPTION_HDR_LEN)
|
|
/* Not the same length */
|
|
return IP_FALSE;
|
|
|
|
return (ipcom_memcmp(server_id, ipdhcps6->duid, server_id_len) == 0);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipdhcps6_msg_add_requsted_opt
|
|
*===========================================================================
|
|
* Description: Adds all options requested by the client and is configured
|
|
* at the server.
|
|
* Parameters: host - The host entry for the requestor.
|
|
* subnet - The matching subnet (can be IP_NULL).
|
|
* oro_opt - The option request option included in the client
|
|
* message.
|
|
* opt - The buffer where the options will be written.
|
|
* optlen - The length of the option buffer, will be updated
|
|
* Returns: IPCOM_SUCCESS - operation was successful.
|
|
* IPCOM_ERR_NO_MEMORY - the 'opt' was not large enough.
|
|
*
|
|
*/
|
|
IP_STATIC Ip_err
|
|
ipdhcps6_msg_add_requsted_opt(Ipdhcps6_host *host,
|
|
Ipdhcps6_subnet_entry *subnet,
|
|
Ipdhcps6_option *oro_opt,
|
|
Ipdhcps6_option *opt,
|
|
Ip_u16 optlen,
|
|
Ip_u16 *bytes_written)
|
|
{
|
|
Ip_u16 oro_code;
|
|
Ip_u16 oro_len;
|
|
Ip_u16 written;
|
|
Ip_u16 resp_buf_len;
|
|
Ipdhcps6_option *resp_opt;
|
|
Ipdhcps6_option *server_opt = IP_NULL;
|
|
int i;
|
|
|
|
ip_assert(host != IP_NULL);
|
|
ip_assert(oro_opt != IP_NULL);
|
|
ip_assert(opt != IP_NULL);
|
|
ip_assert(optlen != IP_NULL);
|
|
|
|
oro_len = ipdhcps6_get_u16(&oro_opt->len);
|
|
ip_assert((oro_len & 1) == 0);
|
|
oro_len /= 2;
|
|
|
|
*bytes_written = 0;
|
|
for (i = 0; i < oro_len; i++)
|
|
{
|
|
oro_code = ipdhcps6_get_u16(&oro_opt->data.request_oro[i]);
|
|
resp_opt = (Ipdhcps6_option *) ((Ip_u8 *) opt + *bytes_written);
|
|
resp_buf_len = (Ip_u16) (optlen - *bytes_written);
|
|
|
|
/*Find FQDN in oro option*/
|
|
if (oro_code == IPDHCPS6_OPTION_FQDN)
|
|
{
|
|
host->fqdn.oro = IP_TRUE;
|
|
continue;
|
|
}
|
|
/* First try host specific options */
|
|
if (host->options != IP_NULL)
|
|
server_opt = ipcom_hash_get(host->options, &oro_code);
|
|
if (server_opt != IP_NULL)
|
|
goto option_found;
|
|
|
|
/* Next try subnet specific options */
|
|
if (subnet != IP_NULL && subnet->options != IP_NULL)
|
|
server_opt = ipcom_hash_get(subnet->options, &oro_code);
|
|
if (server_opt != IP_NULL)
|
|
goto option_found;
|
|
|
|
/* Last, check in global options */
|
|
server_opt = ipcom_hash_get(ipdhcps6->db.options, &oro_code);
|
|
if (server_opt == IP_NULL)
|
|
/* The server does not have a value for this option */
|
|
continue;
|
|
|
|
option_found:
|
|
/* Add the option to the message */
|
|
written = (Ip_u16) (ipdhcps6_get_u16(&server_opt->len) + IPDHCPS6_OPTION_HDR_LEN);
|
|
if (resp_buf_len < written)
|
|
return IPCOM_ERR_NO_MEMORY;
|
|
ipcom_memcpy(resp_opt, server_opt, written);
|
|
*bytes_written += written;
|
|
}
|
|
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipdhcps6_msg_add_opt_cb
|
|
*===========================================================================
|
|
* Description: Adds each option this functions is called with.
|
|
* Parameters: server_opt - A server option.
|
|
* mao - Callback paramters.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipdhcps6_msg_add_opt_cb(Ipdhcps6_option *server_opt, struct Ipdhcps6_msg_add_opt *mao)
|
|
{
|
|
Ip_u16 bytes_written;
|
|
|
|
if (mao->err != IPCOM_SUCCESS)
|
|
return;
|
|
|
|
bytes_written = (Ip_u16) (ipdhcps6_get_u16(&server_opt->len) + IPDHCPS6_OPTION_HDR_LEN);
|
|
|
|
if (mao->optslen < bytes_written)
|
|
{
|
|
mao->err = IPCOM_ERR_NO_MEMORY;
|
|
return;
|
|
}
|
|
ipcom_memcpy(mao->opts, server_opt, bytes_written);
|
|
mao->opts = (Ipdhcps6_option *) ((Ip_u8 *) mao->opts + bytes_written);
|
|
mao->optslen -= bytes_written;
|
|
mao->total_written += bytes_written;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipdhcps6_msg_add_all_opt
|
|
*===========================================================================
|
|
* Description: Adds all options configured at the server.
|
|
* Parameters: host - The host entry for the requestor.
|
|
* subnet - The matching subnet (can be IP_NULL).
|
|
* opt - The buffer where the options will be written.
|
|
* optlen - The length of the option buffer
|
|
* bytes_written - Number of bytes written to the 'opt' buffer.
|
|
* Returns: IPCOM_SUCCESS - operation was successful.
|
|
* IPCOM_ERR_NO_MEMORY - the 'opt' was not large enough.
|
|
*
|
|
*/
|
|
IP_STATIC Ip_err
|
|
ipdhcps6_msg_add_all_opt(Ipdhcps6_host *host, Ipdhcps6_subnet_entry *subnet,
|
|
Ipdhcps6_option *opt, Ip_u16 optlen, Ip_u16 *bytes_written)
|
|
{
|
|
Ipcom_hash *server_opts;
|
|
Ip_err err;
|
|
struct Ipdhcps6_msg_add_opt mao;
|
|
|
|
ip_assert(host != IP_NULL);
|
|
ip_assert(opt != IP_NULL);
|
|
ip_assert(optlen != IP_NULL);
|
|
|
|
server_opts = ipdhcps6_option_new_db();
|
|
if (server_opts == IP_NULL)
|
|
return IPCOM_ERR_NO_MEMORY;
|
|
|
|
/* Merge host specific options */
|
|
if (host->options != IP_NULL)
|
|
{
|
|
err = ipdhcps6_option_merge(server_opts, host->options);
|
|
if (err != IPCOM_SUCCESS)
|
|
return IPCOM_ERR_NO_MEMORY;
|
|
}
|
|
|
|
/* Merge subnet specific options */
|
|
if (subnet != IP_NULL && subnet->options != IP_NULL)
|
|
{
|
|
err = ipdhcps6_option_merge(server_opts, subnet->options);
|
|
if (err != IPCOM_SUCCESS)
|
|
return IPCOM_ERR_NO_MEMORY;
|
|
}
|
|
|
|
/* Merge global options */
|
|
err = ipdhcps6_option_merge(server_opts, ipdhcps6->db.options);
|
|
if (err != IPCOM_SUCCESS)
|
|
return IPCOM_ERR_NO_MEMORY;
|
|
|
|
mao.opts = opt;
|
|
mao.optslen = optlen;
|
|
mao.err = IPCOM_SUCCESS;
|
|
mao.total_written = 0;
|
|
ipcom_hash_for_each(server_opts, (void(*)(void *, void *)) ipdhcps6_msg_add_opt_cb, &mao);
|
|
*bytes_written = mao.total_written;
|
|
ipcom_hash_delete(server_opts);
|
|
return mao.err;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipdhcps6_msg_add_server_options
|
|
*===========================================================================
|
|
* Description: Returns IP_TRUE if the options array contains the server ID
|
|
* for this host.
|
|
* Parameters: subnet - The subnet associated with this request.
|
|
* host - The host associated with this request.
|
|
* request_opts - Pointer to the first option in the request.
|
|
* request_optslen - The length of the request option.
|
|
* response_opt - Pointer to where the first response option
|
|
* should be written.
|
|
* response_optlen - The maximum size of the 'response_opt' buffer.
|
|
* written - Will contain the number of bytes written to 'response_opt'
|
|
* Returns: IPCOM_SUCCESS - operation was successful.
|
|
* IPCOM_ERR_NO_MEMORY - The 'response_opt' was not large enough.
|
|
*
|
|
*/
|
|
IP_STATIC Ip_err
|
|
ipdhcps6_msg_add_server_options(Ipdhcps6_subnet_entry *subnet,
|
|
Ipdhcps6_host *host,
|
|
Ipdhcps6_option *request_opts, Ip_u16 request_optslen,
|
|
Ipdhcps6_option *response_opt, Ip_u16 response_optlen,
|
|
Ip_u16 *written)
|
|
{
|
|
Ip_err err;
|
|
Ipdhcps6_option *oro_opt;
|
|
|
|
*written = 0;
|
|
if (ipdhcps6_option_exist(request_opts, request_optslen, IPDHCPS6_OPTION_ORO))
|
|
{
|
|
/* Only include options asked for by the client */
|
|
|
|
oro_opt = ipdhcps6_option_get_ptr(request_opts, request_optslen, IPDHCPS6_OPTION_ORO);
|
|
err = ipdhcps6_msg_add_requsted_opt(host, subnet, oro_opt, response_opt,
|
|
response_optlen, written);
|
|
}
|
|
else
|
|
{
|
|
/* Include all options appropriate for this subnet/host */
|
|
err = ipdhcps6_msg_add_all_opt(host, subnet, response_opt, response_optlen, written);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipdhcps6_msg_process_fqdn
|
|
*===========================================================================
|
|
* Description: Processes the fqdn option.
|
|
* Parameters: host -where the message comes from
|
|
* opt - all in options
|
|
* request_type - The message type sent by the client.
|
|
* out_opt - Pointer to where the next response option should be written
|
|
* written - Will contain the number of bytes added to 'out_opt'
|
|
* Returns: IPCOM_SUCCESS - operation was successful.
|
|
*
|
|
*/
|
|
|
|
|
|
|
|
IP_STATIC Ip_err
|
|
ipdhcps6_msg_process_fqdn(Ipdhcps6_host *host,
|
|
Ipdhcps6_option* opt,
|
|
Ip_u8 request_type,
|
|
Ipdhcps6_option *out_opt,
|
|
Ip_u16 *written)
|
|
{
|
|
/*Host is not NULL here*/
|
|
/*Need to update flags here*/
|
|
/*Here just add fqdn oro*/
|
|
|
|
/*Flags will be sent*/
|
|
Ip_u8 sflag = 0;
|
|
|
|
/*Get the flags from packet received*/
|
|
Ip_u8 flag = opt->data.generic[0];
|
|
char *domain = (char*)opt->data.generic+1;
|
|
|
|
(void)request_type;
|
|
*written = 0;
|
|
if(ipcom_ntohs(opt->len)<=2)
|
|
{
|
|
/*No name provided from client, at present, log error*/
|
|
IPCOM_LOG0(WARNING, "client must provide a name at fqdn option");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
host->fqdn.agent = 0;
|
|
|
|
if (IP_BIT_ISSET(flag, IPDHCPS6_FQDN_FLAG_N))
|
|
/*Server does none update*/
|
|
/*Fqdn needs return back*/
|
|
IP_BIT_SET(sflag, IPDHCPS6_FQDN_FLAG_N);
|
|
else
|
|
{
|
|
if (IP_BIT_ISSET(flag, IPDHCPS6_FQDN_FLAG_S))
|
|
{
|
|
if(ipcom_sysvar_get_as_int("ipdhcps6.fqdn.allow.update", 1))
|
|
{
|
|
host->fqdn.agent = 1;
|
|
IP_BIT_SET(sflag, IPDHCPS6_FQDN_FLAG_S);
|
|
}
|
|
else
|
|
IP_BIT_SET(sflag, IPDHCPS6_FQDN_FLAG_O);
|
|
}
|
|
}
|
|
|
|
if (host->fqdn.oro)
|
|
{
|
|
|
|
Ip_u8 dc_len = 0;
|
|
char *payload =(char*) out_opt->data.generic ;
|
|
char *dc_len_ptr = IP_NULL;
|
|
char domainname[128];
|
|
|
|
out_opt->code = ipcom_htons(IPDHCPS6_OPTION_FQDN);
|
|
*payload = sflag;
|
|
payload++;
|
|
|
|
ipcom_strncpy(payload+1, domain+1,*domain);
|
|
*(payload+1+*domain) = '\0';
|
|
/*End with '\0'*/
|
|
ipcom_strcat(payload+1,".");
|
|
|
|
if(ipdhcps6_dns_get_domain(domainname))
|
|
ipcom_strcat(payload+1,domainname);
|
|
else
|
|
{
|
|
IPCOM_LOG0(WARNING, "no domainname found at fqdn option");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
out_opt->len = ipcom_htons(1+1+ipcom_strlen(payload+1)+1);
|
|
/*1--flag,1--first len--1---'\0'*/
|
|
do
|
|
{
|
|
dc_len = 0;
|
|
dc_len_ptr = payload++;
|
|
while (*payload != '.' && *payload != '\0')
|
|
{
|
|
++dc_len;
|
|
++payload;
|
|
}
|
|
*dc_len_ptr = dc_len;
|
|
|
|
}
|
|
while (*payload != '\0');
|
|
/*Add the fqdn to response message*/
|
|
*written = ipcom_ntohs(out_opt->len)+IPDHCPS6_OPTION_HDR_LEN;
|
|
}
|
|
|
|
host->fqdn.oro = IP_FALSE;
|
|
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
/*
|
|
*===========================================================================
|
|
* ipdhcps6_msg_process_rapid_commit
|
|
*===========================================================================
|
|
* Description: Processes the rapid commit option.
|
|
* Parameters: request_type - The message type sent by the client.
|
|
* out_opt - Pointer to where the next response option should
|
|
* be written
|
|
* written - Will contain the number of bytes added to 'out_opt'
|
|
* Returns: IPCOM_SUCCESS - operation was successful.
|
|
*
|
|
*/
|
|
IP_STATIC Ip_err
|
|
ipdhcps6_msg_process_rapid_commit(Ip_u8 request_type,
|
|
Ipdhcps6_option *out_opt,
|
|
Ip_u16 *written)
|
|
{
|
|
char str[4];
|
|
Ip_size_t str_len = sizeof(str);
|
|
|
|
*written = 0;
|
|
|
|
if (request_type != IPDHCPS6_MSG_SOLICIT)
|
|
IPCOM_LOG0(NOTICE, "Ignoring rapid commit option on non-solicit message");
|
|
else
|
|
{
|
|
char *cfg = ipcom_sysvar_get("ipdhcps6.server.allow_rapid_commit",
|
|
str, &str_len);
|
|
if (cfg && ipcom_strcmp("yes", cfg) != 0)
|
|
{
|
|
IPCOM_LOG0(NOTICE, "Ignoring rapid commit option since it is administratively disabled");
|
|
}
|
|
else
|
|
{
|
|
ipdhcps6_set_u16(&out_opt->code, IPDHCPS6_OPTION_RAPID_COMMIT);
|
|
ipdhcps6_set_u16(&out_opt->len, 0);
|
|
*written = IPDHCPS6_OPTION_HDR_LEN;
|
|
}
|
|
}
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipdhcps6_msg_process_options
|
|
*===========================================================================
|
|
* Description: Returns IP_TRUE if the options array contains the server ID
|
|
* for this host.
|
|
* Parameters: options - An array of options.
|
|
* optslen - The length of the 'options' buffer.
|
|
* Returns: IPCOM_SUCCESS - operation was successful.
|
|
* IPCOM_ERR_NO_MEMORY - out of memory.
|
|
*
|
|
*/
|
|
IP_STATIC Ip_err
|
|
ipdhcps6_msg_process_options(Ipdhcps6_message *msg, Ipdhcps6_option *options, Ip_u16 optslen)
|
|
{
|
|
Ipdhcps6_option *opt;
|
|
Ipdhcps6_msg_hdr *request;
|
|
Ipdhcps6_msg_hdr *response;
|
|
Ipdhcps6_option *response_opt;
|
|
Ip_u16 response_optlen;
|
|
Ip_u16 opt_code;
|
|
Ip_u16 written;
|
|
Ipdhcps6_subnet_entry *subnet;
|
|
Ipdhcps6_host *host;
|
|
Ipdhcps6_option *clientid;
|
|
Ip_err err = 0;
|
|
Ipcom_netif *netif = IP_NULL;
|
|
|
|
request = (Ipdhcps6_msg_hdr *) msg->recv_buf;
|
|
response = (Ipdhcps6_msg_hdr *) msg->send_buf;
|
|
|
|
/* Write the message header to the respose */
|
|
response->type = IPDHCPS6_MSG_REPLY;
|
|
IPDHCPS6_CPY_TRANSACTION_ID(response, request);
|
|
ipdhcps6_msg_first_response_opt(msg, &response_opt, &response_optlen);
|
|
|
|
/* Add the server ID */
|
|
if (ipdhcps6_option_add_server_id(response_opt, response_optlen, &written) != IPCOM_SUCCESS)
|
|
{
|
|
err = IPCOM_ERR_FAILED;
|
|
goto done;
|
|
}
|
|
ipdhcps6_msg_next_response_opt(written, msg, &response_opt, &response_optlen);
|
|
|
|
/* Add the supplied client ID to the reponse */
|
|
if (ipdhcps6_option_get(options, optslen, IPDHCPS6_OPTION_CLIENTID,
|
|
response_opt, response_optlen, &written) != IPCOM_SUCCESS)
|
|
{
|
|
/* Client ID must be present before calling this function. */
|
|
err = IPCOM_ERR_FAILED;
|
|
goto done;
|
|
}
|
|
clientid = response_opt;
|
|
ipdhcps6_msg_next_response_opt(written, msg, &response_opt, &response_optlen);
|
|
|
|
/* Find the host and subnet entries matching this request */
|
|
subnet = ipdhcps6_subnet_get_from_addr(&msg->peer_addr.sin6_addr, (int)msg->ifindex);
|
|
host = ipdhcps6_host_get(clientid);
|
|
if (host == IP_NULL)
|
|
{
|
|
if (subnet == IP_NULL)
|
|
{
|
|
/* Unknown host and using a unconfigured subnet, drop the message */
|
|
IPCOM_LOG1(DEBUG,
|
|
"Sending error response to %s, no configuration found for that subnet",
|
|
ipcom_inet_ntop(IP_AF_INET6,
|
|
&msg->peer_addr.sin6_addr,
|
|
ipdhcps6->addr_str,
|
|
sizeof(ipdhcps6->addr_str)));
|
|
|
|
err = ipdhcps6_option_add_status_code(response_opt,
|
|
response_optlen,
|
|
&written,
|
|
IPDHCPS6_CODE_NO_BINDING,
|
|
"No configuration for this subnet or host.");
|
|
if (err != IPCOM_SUCCESS)
|
|
goto done;
|
|
|
|
ipdhcps6_msg_next_response_opt(written, msg, &response_opt, &response_optlen);
|
|
goto done_send_response;
|
|
}
|
|
/* Create a new host structure */
|
|
host = ipdhcps6_host_new(clientid, &msg->peer_addr);
|
|
if (host == IP_NULL)
|
|
{
|
|
IPCOM_LOG1(DEBUG, "Dropping message from %s, failed to create host entry (out of memory)",
|
|
ipcom_inet_ntop(IP_AF_INET6, &msg->peer_addr.sin6_addr, ipdhcps6->addr_str, sizeof(ipdhcps6->addr_str)));
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
netif = ipdhcps6_get_netifbyindex(msg->ifindex);
|
|
ip_assert(IP_NULL != netif);
|
|
|
|
ipdhcps6_host_try_get_user(host, netif);
|
|
|
|
ip_assert(host != IP_NULL);
|
|
host->last_servered = ipcom_time(IP_NULL);
|
|
|
|
if (ipdhcps6_option_exist(options, optslen, IPDHCPS6_OPTION_IAADDR)
|
|
|| ipdhcps6_option_exist(options, optslen, IPDHCPS6_OPTION_IAPREFIX))
|
|
{
|
|
/* RFC 3315 chapter 22.6
|
|
The IA Address option is used to specify IPv6 addresses associated
|
|
with an IA_NA or an IA_TA.
|
|
*/
|
|
err = ipdhcps6_option_add_status_code(response_opt,
|
|
response_optlen,
|
|
&written,
|
|
IPDHCPS6_CODE_UNSPEC_FAIL,
|
|
"Invalid option in request");
|
|
/* start for defect WIND00228550 */
|
|
if (err != IPCOM_SUCCESS)
|
|
goto done;
|
|
|
|
ipdhcps6_msg_next_response_opt(written, msg, &response_opt, &response_optlen);
|
|
/* end for defect WIND00228550 */
|
|
goto done_send_response;
|
|
}
|
|
|
|
if (request->type == IPDHCPS6_MSG_INFORMATION_REQUEST)
|
|
{
|
|
/* RFC 3315 chapter 15
|
|
If a server receives a message that contains options it should not
|
|
contain (such as an Information-request message with an IA option),
|
|
is missing options that it should contain, or is otherwise not valid,
|
|
it MAY send a Reply (or Advertise as appropriate) with a Server
|
|
Identifier option, a Client Identifier option if one was included in
|
|
the message and a Status Code option with status UnSpecFail.*/
|
|
if (ipdhcps6_option_exist(options, optslen, IPDHCPS6_OPTION_IA_TA)
|
|
|| ipdhcps6_option_exist(options, optslen, IPDHCPS6_OPTION_IA_NA))
|
|
{
|
|
err = ipdhcps6_option_add_status_code(response_opt,
|
|
response_optlen,
|
|
&written,
|
|
IPDHCPS6_CODE_UNSPEC_FAIL,
|
|
"Not allowed to request addresses in an information-request");
|
|
/* start for defect WIND00228550 */
|
|
if (err != IPCOM_SUCCESS)
|
|
goto done;
|
|
|
|
ipdhcps6_msg_next_response_opt(written, msg, &response_opt, &response_optlen);
|
|
/* end for defect WIND00228550 */
|
|
|
|
goto done_send_response;
|
|
}
|
|
}
|
|
|
|
if (host->is_allowed_to_use_unicast == IP_FALSE &&
|
|
IP_IN6_IS_ADDR_MULTICAST(&msg->local_addr.sin6_addr) == IP_FALSE)
|
|
{
|
|
/* Coverity defect fix for DEADCODE */
|
|
err = ipdhcps6_option_add_status_code(response_opt, response_optlen, &written,
|
|
IPDHCPS6_CODE_USE_MULTICAST, "Must use multicast");
|
|
/* start for defect WIND00228550 */
|
|
if (err != IPCOM_SUCCESS)
|
|
goto done;
|
|
|
|
ipdhcps6_msg_next_response_opt(written, msg, &response_opt, &response_optlen);
|
|
/* end for defect WIND00228550 */
|
|
goto done_send_response;
|
|
}
|
|
|
|
/* Add server options to the response */
|
|
err = ipdhcps6_msg_add_server_options(subnet, host, options, optslen,
|
|
response_opt, response_optlen, &written);
|
|
/*do nothing in this fucntion*/
|
|
if (err != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG1(DEBUG, "Dropping message from %s, failed to create response (too small buffer)",
|
|
ipcom_inet_ntop(IP_AF_INET6, &msg->peer_addr.sin6_addr, ipdhcps6->addr_str, sizeof(ipdhcps6->addr_str)));
|
|
goto done;
|
|
}
|
|
ipdhcps6_msg_next_response_opt(written, msg, &response_opt, &response_optlen);
|
|
|
|
/* Iterate through all options sent by the client */
|
|
for (opt = options; opt != IP_NULL; opt = ipdhcps6_option_next(opt, &optslen))
|
|
{
|
|
/* Cannot use 'normal' assignment since opt might be located on an odd address */
|
|
opt_code = ipdhcps6_get_u16(&opt->code);
|
|
switch (opt_code)
|
|
{
|
|
case IPDHCPS6_OPTION_FQDN:
|
|
err = ipdhcps6_msg_process_fqdn(host, opt, request->type, response_opt, &written);
|
|
break;
|
|
case IPDHCPS6_OPTION_RAPID_COMMIT:
|
|
err = ipdhcps6_msg_process_rapid_commit(request->type,
|
|
response_opt,
|
|
&written);
|
|
break;
|
|
case IPDHCPS6_OPTION_IA_NA:
|
|
err = ipdhcps6_pool_process_non_temporary_addr_request(request->type,
|
|
subnet,
|
|
host,
|
|
opt,
|
|
response_opt,
|
|
response_optlen,
|
|
&written);
|
|
|
|
|
|
break;
|
|
case IPDHCPS6_OPTION_IA_TA:
|
|
IPCOM_LOG0(WARNING, "Assigning of temporary addresses not implemented yet");
|
|
err = ipdhcps6_option_add_status_code(response_opt,
|
|
response_optlen,
|
|
&written,
|
|
IPDHCPS6_CODE_NO_ADDRS_AVAIL,
|
|
"Assigning of temporary addresses not implemented yet");
|
|
goto done_send_response;
|
|
case IPDHCPS6_OPTION_IA_PD:
|
|
switch (netif->type)
|
|
{
|
|
#ifdef IPPPP
|
|
case IP_IFT_PPP:
|
|
err = ipdhcps6_prefix_process_request(request->type,
|
|
subnet,
|
|
host,
|
|
opt,
|
|
response_opt,
|
|
response_optlen,
|
|
&written);
|
|
break;
|
|
#endif /* IPPPP */
|
|
/* more type if needed */
|
|
default:
|
|
err = ipdhcps6_pool_process_prefix_delegation_request(request->type,
|
|
subnet,
|
|
host,
|
|
opt,
|
|
response_opt,
|
|
response_optlen,
|
|
&written);
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
continue;
|
|
}
|
|
if (err != IPCOM_SUCCESS)
|
|
goto done;
|
|
ipdhcps6_msg_next_response_opt(written, msg, &response_opt, &response_optlen);
|
|
}
|
|
|
|
done_send_response:
|
|
msg->send_response = IP_TRUE;
|
|
|
|
done:
|
|
if (IPCOM_SUCCESS != err)
|
|
IPCOM_LOG2(ERR,
|
|
"Failed to create a response for %s, err = %d",
|
|
ipcom_inet_ntop(IP_AF_INET6, &msg->peer_addr.sin6_addr,
|
|
ipdhcps6->addr_str, sizeof(ipdhcps6->addr_str)),
|
|
err);
|
|
return err;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipdhcps6_msg_check_client_and_server_id
|
|
*===========================================================================
|
|
* Description: Checks is server & client ID exists and that server ID
|
|
* matches this server.
|
|
* Parameters: msg - The request/response message structure.
|
|
* Returns: IP_TRUE if client & server ID exists and server ID matches
|
|
* this server.
|
|
*
|
|
*/
|
|
IP_STATIC Ip_bool
|
|
ipdhcps6_msg_check_client_and_server_id(Ipdhcps6_message *msg,
|
|
Ipdhcps6_option *options,
|
|
Ip_u16 optslen,
|
|
const char *msg_type)
|
|
{
|
|
/* Must contain Client Identifier and Server Identifier options */
|
|
if (ipdhcps6_option_exist(options, optslen, IPDHCPS6_OPTION_CLIENTID) == IP_FALSE)
|
|
{
|
|
/* Discard the message since it is invalid */
|
|
IPCOM_LOG2(INFO, "Discarding %s message received from %s since client ID is missing",
|
|
msg_type,
|
|
ipcom_inet_ntop(IP_AF_INET6, &msg->peer_addr.sin6_addr, ipdhcps6->addr_str, sizeof(ipdhcps6->addr_str)));
|
|
return IP_FALSE;
|
|
}
|
|
|
|
if (ipdhcps6_msg_contains_local_server_id(options, optslen) == IP_FALSE)
|
|
{
|
|
/* Does not contain the server ID for this host, just drop the message */
|
|
IPCOM_LOG2(DEBUG, "Discarding %s message received from %s since "
|
|
"server ID is missing or does not match local server ID",
|
|
msg_type,
|
|
ipcom_inet_ntop(IP_AF_INET6, &msg->peer_addr.sin6_addr,
|
|
ipdhcps6->addr_str, sizeof(ipdhcps6->addr_str)));
|
|
return IP_FALSE;
|
|
}
|
|
return IP_TRUE;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipdhcps6_msg_check_IA_infor
|
|
*===========================================================================
|
|
* Description: Checks if IA information exists.
|
|
* Parameters: msg - The request/response message structure.
|
|
* Returns: IP_TRUE if exists, else IP_FALSE.
|
|
*
|
|
*/
|
|
IP_STATIC Ip_bool
|
|
ipdhcps6_msg_check_IA_infor(Ipdhcps6_message *msg,
|
|
Ipdhcps6_option *options,
|
|
Ip_u16 optslen,
|
|
const char *msg_type)
|
|
{
|
|
if (ipdhcps6_option_exist(options, optslen, IPDHCPS6_OPTION_IA_NA))
|
|
{
|
|
/* Discard the message since it is invalid */
|
|
IPCOM_LOG2(INFO, "Discarding %s message received from %s since including IA_NA.",
|
|
msg_type,
|
|
ipcom_inet_ntop(IP_AF_INET6, &msg->peer_addr.sin6_addr, ipdhcps6->addr_str, sizeof(ipdhcps6->addr_str)));
|
|
return IP_FALSE;
|
|
}
|
|
|
|
if (ipdhcps6_option_exist(options, optslen, IPDHCPS6_OPTION_IA_TA))
|
|
{
|
|
/* Discard the message since it is invalid */
|
|
IPCOM_LOG2(INFO, "Discarding %s message received from %s since including IA_TA.",
|
|
msg_type,
|
|
ipcom_inet_ntop(IP_AF_INET6, &msg->peer_addr.sin6_addr, ipdhcps6->addr_str, sizeof(ipdhcps6->addr_str)));
|
|
return IP_FALSE;
|
|
}
|
|
|
|
/* XXX : IA_PD */
|
|
if (ipdhcps6_option_exist(options, optslen, IPDHCPS6_OPTION_IA_PD))
|
|
{
|
|
/* Discard the message since it is invalid */
|
|
IPCOM_LOG2(INFO, "Discarding %s message received from %s since including IA_PD.",
|
|
msg_type,
|
|
ipcom_inet_ntop(IP_AF_INET6, &msg->peer_addr.sin6_addr, ipdhcps6->addr_str, sizeof(ipdhcps6->addr_str)));
|
|
return IP_FALSE;
|
|
}
|
|
|
|
return IP_TRUE;
|
|
}
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 10 GLOBAL FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipdhcps6_msg_get_first_option
|
|
*===========================================================================
|
|
* Description: Returns a pointer to the first option in the message.
|
|
* Parameters: msg - The DHCP message.
|
|
* msg_len - The length of the message.
|
|
* poptions - Will contain a pointer to the first message.
|
|
* poptslen - Will contain the total length of all options.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipdhcps6_msg_get_first_option(Ipdhcps6_msg_hdr *msg,
|
|
Ip_u16 msg_len,
|
|
Ipdhcps6_option **poptions,
|
|
Ip_u16 *poptslen)
|
|
{
|
|
Ip_u16 header_len = IPDHCPS6_MSG_HDR_LEN;
|
|
|
|
if (msg->type == IPDHCPS6_MSG_RELAY_FORW
|
|
|| msg->type == IPDHCPS6_MSG_RELAY_REPL)
|
|
header_len = IPDHCP_RELAY_MSG_HDR_LEN;
|
|
|
|
ip_assert(msg_len > header_len);
|
|
*poptslen = msg_len - header_len;
|
|
*poptions = (Ipdhcps6_option *) ((Ip_u8 *) msg + header_len);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipdhcps6_msg_first_response_opt
|
|
*===========================================================================
|
|
* Description: Moves the 'response_opt' pointer to the address where the
|
|
* next option can be written.
|
|
* Parameters: msg - The request/response message structure.
|
|
* reponse_opt - Will contain a pointer to where the next option
|
|
* should be located.
|
|
* optlen - Will contain the number of bytes left of the response
|
|
* buffer.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipdhcps6_msg_first_response_opt(Ipdhcps6_message *msg,
|
|
Ipdhcps6_option **response_opt,
|
|
Ip_u16 *optlen)
|
|
{
|
|
Ip_u16 header_len = IPDHCPS6_MSG_HDR_LEN;
|
|
Ipdhcps6_msg_hdr *msg_header = (Ipdhcps6_msg_hdr *) msg->send_buf;
|
|
|
|
if (msg_header->type == IPDHCPS6_MSG_RELAY_FORW
|
|
|| msg_header->type == IPDHCPS6_MSG_RELAY_REPL)
|
|
header_len = IPDHCP_RELAY_MSG_HDR_LEN;
|
|
|
|
ip_assert(msg->send_buf_maxlen > header_len);
|
|
msg->send_buf_len = header_len;
|
|
*optlen = (Ip_u16) (msg->send_buf_maxlen - msg->send_buf_len);
|
|
*response_opt = (Ipdhcps6_option *) &msg->send_buf[msg->send_buf_len];
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipdhcps6_msg_next_response_opt
|
|
*===========================================================================
|
|
* Description: Moves the 'response_opt' pointer to the address where the
|
|
* next option can be written.
|
|
* Parameters: written - Number of bytes written to 'current'.
|
|
* msg - The request/response message structure.
|
|
* next_response_opt - Will contain a pointer to where the next option
|
|
* should be located.
|
|
* opt_buf_left - Will contain the number of bytes left of the response
|
|
* buffer.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipdhcps6_msg_next_response_opt(Ip_u16 written,
|
|
Ipdhcps6_message *msg,
|
|
Ipdhcps6_option **next_response_opt,
|
|
Ip_u16 *opt_buf_left)
|
|
{
|
|
msg->send_buf_len += written;
|
|
ip_assert(msg->send_buf_maxlen >= msg->send_buf_len);
|
|
*opt_buf_left = (Ip_u16) (msg->send_buf_maxlen - msg->send_buf_len);
|
|
*next_response_opt = (Ipdhcps6_option *) &msg->send_buf[msg->send_buf_len];
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipdhcps6_msg_type_to_string
|
|
*===========================================================================
|
|
* Description: Returns a string representation of the message type.
|
|
* Parameters: type - The message type.
|
|
* Returns: A string representation.
|
|
*
|
|
*/
|
|
IP_GLOBAL const char *
|
|
ipdhcps6_msg_type_to_string(Ip_u8 type)
|
|
{
|
|
static char num_str[20];
|
|
|
|
switch (type)
|
|
{
|
|
case IPDHCPS6_MSG_SOLICIT:
|
|
return "MSG_SOLICIT";
|
|
case IPDHCPS6_MSG_ADVERTISE:
|
|
return "MSG_ADVERTISE";
|
|
case IPDHCPS6_MSG_REQUEST:
|
|
return "MSG_REQUEST";
|
|
case IPDHCPS6_MSG_CONFIRM:
|
|
return "MSG_CONFIRM";
|
|
case IPDHCPS6_MSG_RENEW:
|
|
return "MSG_RENEW";
|
|
case IPDHCPS6_MSG_REBIND:
|
|
return "MSG_REBIND";
|
|
case IPDHCPS6_MSG_REPLY:
|
|
return "MSG_REPLY";
|
|
case IPDHCPS6_MSG_RELEASE:
|
|
return "MSG_RELEASE";
|
|
case IPDHCPS6_MSG_DECLINE:
|
|
return "MSG_DECLINE";
|
|
case IPDHCPS6_MSG_RECONFIGURE:
|
|
return "MSG_RECONFIGURE";
|
|
case IPDHCPS6_MSG_INFORMATION_REQUEST:
|
|
return "MSG_INFORMATION_REQUEST";
|
|
case IPDHCPS6_MSG_RELAY_FORW:
|
|
return "MSG_RELAY_FORW";
|
|
case IPDHCPS6_MSG_RELAY_REPL:
|
|
return "MSG_RELAY_REPL";
|
|
}
|
|
ipcom_sprintf(num_str, "Unknown type: %d", type);
|
|
return num_str;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipdhcps6_msg_process_solicit
|
|
*===========================================================================
|
|
* Description: Handles Solicit message.
|
|
* Parameters: msg - The received message, will contain the reply if such
|
|
* should be sent.
|
|
* options - Points to the first option included in the client
|
|
* message. All options are packed into this buffer without padding.
|
|
* optslen - The length of all options in the buffer pointer to
|
|
* by 'options'.
|
|
* Returns: IPCOM_SUCCESS - message was processed successfully (dropped
|
|
* messages also counts as successful processing).
|
|
* IPCOM_ERR_FAILED - critical error encountered.
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipdhcps6_msg_process_solicit(Ipdhcps6_message *msg,
|
|
Ipdhcps6_option *options,
|
|
Ip_u16 optslen)
|
|
{
|
|
Ip_err err;
|
|
|
|
/* PSERVITA */
|
|
Ipdhcps6_option clientid_option;
|
|
union Ipdhcps6_duid_data *client_duid;
|
|
|
|
Ip_u16 wbytes;
|
|
Ip_err status;
|
|
|
|
status = ipdhcps6_option_get(options, optslen, IPDHCPS6_OPTION_CLIENTID,
|
|
&clientid_option, sizeof (clientid_option), &wbytes);
|
|
|
|
if (IPCOM_SUCCESS != status)
|
|
{ /*
|
|
* no client id! reject this packet.
|
|
*/
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
clientid_option.len = ip_ntohs(clientid_option.len);
|
|
|
|
client_duid = (union Ipdhcps6_duid_data *) &(clientid_option.data);
|
|
|
|
if (ipdhcps6_option_exist(options, optslen, IPDHCPS6_OPTION_AUTH) == IP_TRUE)
|
|
{
|
|
/*
|
|
* add client into the "wants auth" database,
|
|
* if not already there.
|
|
*/
|
|
if (IP_NULL == ipdhcps6_client_requested_auth (client_duid, clientid_option.len))
|
|
ipdhcps6_client_wants_auth (client_duid, clientid_option.len);
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
*client has not requested AUTH.
|
|
* remove them from the authtrans db
|
|
*/
|
|
ipdhcps6_client_no_auth (client_duid, clientid_option.len);
|
|
}
|
|
/* PSERVITA */
|
|
|
|
err = ipdhcps6_msg_process_rebind(msg, options, optslen);
|
|
if (err != IPCOM_SUCCESS)
|
|
return err;
|
|
|
|
if (msg->send_response)
|
|
{
|
|
Ipdhcps6_msg_hdr *response= (Ipdhcps6_msg_hdr *) msg->send_buf;
|
|
|
|
ipdhcps6_msg_get_first_option((Ipdhcps6_msg_hdr *) msg->send_buf,
|
|
msg->send_buf_len,
|
|
&options,
|
|
&optslen);
|
|
if (ipdhcps6_option_exist(options, optslen, IPDHCPS6_OPTION_RAPID_COMMIT) == IP_FALSE)
|
|
response->type = IPDHCPS6_MSG_ADVERTISE;
|
|
/* else: Handle this in the same way as a Request message */
|
|
}
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipdhcps6_msg_process_confirm
|
|
*===========================================================================
|
|
* Description: Handles Request message.
|
|
* Parameters: msg - The received message, will contain the reply if such
|
|
* should be sent.
|
|
* options - Points to the first option included in the client
|
|
* message. All options are packed into this buffer without padding.
|
|
* optslen - The length of all options in the buffer pointer to
|
|
* by 'options'.
|
|
* Returns: IPCOM_SUCCESS - message was processed successfully (dropped
|
|
* messages also counts as successful processing).
|
|
* IPCOM_ERR_FAILED - critical error encountered.
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipdhcps6_msg_process_confirm(Ipdhcps6_message *msg,
|
|
Ipdhcps6_option *options,
|
|
Ip_u16 optslen)
|
|
{
|
|
/* The information-request specific processing is located in
|
|
ipdhcps6_msg_process_options() since they require a response
|
|
which in turn requires a valid response message */
|
|
return ipdhcps6_msg_process_rebind(msg, options, optslen);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipdhcps6_msg_process_information_request
|
|
*===========================================================================
|
|
* Description: Handles Request message.
|
|
* Parameters: msg - The received message, will contain the reply if such
|
|
* should be sent.
|
|
* options - Points to the first option included in the client
|
|
* message. All options are packed into this buffer without padding.
|
|
* optslen - The length of all options in the buffer pointer to
|
|
* by 'options'.
|
|
* Returns: IPCOM_SUCCESS - message was processed successfully (dropped
|
|
* messages also counts as successful processing).
|
|
* IPCOM_ERR_FAILED - critical error encountered.
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipdhcps6_msg_process_information_request(Ipdhcps6_message *msg,
|
|
Ipdhcps6_option *options,
|
|
Ip_u16 optslen)
|
|
{
|
|
/* For TAHI, but it is OK with the process in ipdhcps6_msg_process_options */
|
|
if (ipdhcps6_msg_check_IA_infor(msg, options, optslen, "information request"))
|
|
return ipdhcps6_msg_process_rebind(msg, options, optslen);
|
|
return IPCOM_ERR_IGNORED_PACKET;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipdhcps6_msg_process_request
|
|
*===========================================================================
|
|
* Description: Handles Request message.
|
|
* Parameters: msg - The received message, will contain the reply if such
|
|
* should be sent.
|
|
* options - Points to the first option included in the client
|
|
* message. All options are packed into this buffer without padding.
|
|
* optslen - The length of all options in the buffer pointer to
|
|
* by 'options'.
|
|
* Returns: IPCOM_SUCCESS - message was processed successfully (dropped
|
|
* messages also counts as successful processing).
|
|
* IPCOM_ERR_FAILED - critical error encountered.
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipdhcps6_msg_process_request(Ipdhcps6_message *msg,
|
|
Ipdhcps6_option *options, Ip_u16 optslen)
|
|
{
|
|
if (ipdhcps6_msg_check_client_and_server_id(msg, options, optslen, "request"))
|
|
return ipdhcps6_msg_process_options(msg, options, optslen);
|
|
return IPCOM_ERR_IGNORED_PACKET;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipdhcps6_msg_process_renew
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipdhcps6_msg_process_renew(Ipdhcps6_message *msg,
|
|
Ipdhcps6_option *options,
|
|
Ip_u16 optslen)
|
|
{
|
|
Ipdhcps6_option *client_id;
|
|
|
|
if (ipdhcps6_msg_check_client_and_server_id(msg, options, optslen, "renew") == IP_FALSE)
|
|
return IPCOM_SUCCESS;
|
|
|
|
client_id = ipdhcps6_option_get_ptr(options, optslen, IPDHCPS6_OPTION_CLIENTID);
|
|
ip_assert(client_id != IP_NULL);
|
|
if (ipdhcps6_host_get(client_id) == IP_NULL)
|
|
{
|
|
/* This host has not been served before, so RENEW is not possible
|
|
drop the message */
|
|
IPCOM_LOG1(DEBUG, "Discarding renew message received from %s since "
|
|
"this host has not been served since last restart of this server",
|
|
ipcom_inet_ntop(IP_AF_INET6, &msg->peer_addr.sin6_addr,
|
|
ipdhcps6->addr_str, sizeof(ipdhcps6->addr_str)));
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
return ipdhcps6_msg_process_options(msg, options, optslen);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipdhcps6_msg_process_rebind
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipdhcps6_msg_process_rebind(Ipdhcps6_message * msg,
|
|
Ipdhcps6_option *options,
|
|
Ip_u16 optslen)
|
|
{
|
|
Ipdhcps6_msg_hdr *request = (Ipdhcps6_msg_hdr *) msg->recv_buf;
|
|
|
|
/* RFC 3315 chapter 15.
|
|
A server MUST discard any Solicit, Confirm, Rebind or
|
|
Information-request messages it receives with a unicast destination
|
|
address. */
|
|
if (IP_IN6_IS_ADDR_MULTICAST(&msg->local_addr.sin6_addr) == IP_FALSE)
|
|
{
|
|
IPCOM_LOG2(INFO,
|
|
"Discarding %s message received from %s since it was sent to a unicast address",
|
|
ipdhcps6_msg_type_to_string(request->type),
|
|
ipcom_inet_ntop(IP_AF_INET6,
|
|
&msg->peer_addr.sin6_addr,
|
|
ipdhcps6->addr_str,
|
|
sizeof(ipdhcps6->addr_str)));
|
|
return IPCOM_ERR_IGNORED_PACKET;
|
|
}
|
|
|
|
/* RFC 3315 chapter 15.7
|
|
Must contain Client Identifier option
|
|
and must NOT include Server Identifier option*/
|
|
if (ipdhcps6_option_exist(options, optslen, IPDHCPS6_OPTION_CLIENTID) == IP_FALSE
|
|
|| ipdhcps6_option_exist(options, optslen, IPDHCPS6_OPTION_SERVERID))
|
|
{
|
|
/* Discard the message */
|
|
IPCOM_LOG2(INFO,
|
|
"Discarding %s message received from %s since client ID is missing"
|
|
" and/or server ID is present",
|
|
ipdhcps6_msg_type_to_string(request->type),
|
|
ipcom_inet_ntop(IP_AF_INET6,
|
|
&msg->peer_addr.sin6_addr,
|
|
ipdhcps6->addr_str,
|
|
sizeof(ipdhcps6->addr_str)));
|
|
return IPCOM_ERR_IGNORED_PACKET;
|
|
}
|
|
return ipdhcps6_msg_process_options(msg, options, optslen);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipdhcps6_msg_process_release
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipdhcps6_msg_process_release(Ipdhcps6_message * msg,
|
|
Ipdhcps6_option *options,
|
|
Ip_u16 optslen)
|
|
{
|
|
if (ipdhcps6_msg_check_client_and_server_id(msg, options, optslen, "release"))
|
|
return ipdhcps6_msg_process_options(msg, options, optslen);
|
|
return IPCOM_ERR_IGNORED_PACKET;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipdhcps6_msg_process_decline
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipdhcps6_msg_process_decline(Ipdhcps6_message * msg,
|
|
Ipdhcps6_option *options,
|
|
Ip_u16 optslen)
|
|
{
|
|
/*we start to deal decline message*/
|
|
|
|
if (ipdhcps6_msg_check_client_and_server_id(msg, options, optslen, "decline"))
|
|
return ipdhcps6_msg_process_options(msg, options, optslen);
|
|
return IPCOM_ERR_IGNORED_PACKET;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipdhcps6_msg_process_relay_forw
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipdhcps6_msg_process_relay_forw(Ipdhcps6_message *msg,
|
|
Ipdhcps6_option *in_opts,
|
|
Ip_u16 in_opts_len)
|
|
{
|
|
Ipdhcps6_option *reply_opt;
|
|
Ip_u16 reply_opt_len;
|
|
Ip_u16 written;
|
|
Ipdhcps6_option *relay_message_opt;
|
|
Ipdhcps6_option *interface_id_opt;
|
|
Ipdhcps6_relay_msg_hdr *response;
|
|
Ipdhcps6_relay_msg_hdr *request;
|
|
Ipdhcps6_message inner_msg = *msg;
|
|
Ip_err err;
|
|
|
|
response = (Ipdhcps6_relay_msg_hdr *) msg->send_buf;
|
|
request = (Ipdhcps6_relay_msg_hdr *) msg->recv_buf;
|
|
|
|
relay_message_opt = ipdhcps6_option_get_ptr(in_opts,
|
|
in_opts_len,
|
|
IPDHCPS6_OPTION_RELAY_MSG);
|
|
if (relay_message_opt == IP_NULL)
|
|
{
|
|
IPCOM_LOG0(INFO, "Ignoring relay-forward packet since it does not contain a relay message option");
|
|
return IPCOM_ERR_IGNORED_PACKET;
|
|
}
|
|
|
|
/* Create the relay-reply header */
|
|
IPDHCPS6_SET_IN6_ADDR(&inner_msg.peer_addr.sin6_addr, &request->link_addr);
|
|
/* Process the inner message as if it has been sent to a multicast address
|
|
since the relay agents is always allowed to use unicast */
|
|
IPDHCPS6_SET_IN6_ADDR(&inner_msg.local_addr.sin6_addr, &ipdhcps6_all_dhcp_servers);
|
|
inner_msg.local_addr.sin6_scope_id = 0;
|
|
inner_msg.recv_buf = (void*) &relay_message_opt->data;
|
|
inner_msg.recv_buf_len -= (Ip_u16) ((Ip_ptrdiff_t) inner_msg.recv_buf
|
|
- (Ip_ptrdiff_t) msg->recv_buf);
|
|
ipcom_memcpy(response, request, IPDHCP_RELAY_MSG_HDR_LEN);
|
|
response->type = IPDHCPS6_MSG_RELAY_REPL;
|
|
|
|
/* Add the Relay Message to the response */
|
|
ipdhcps6_msg_first_response_opt(msg,
|
|
&reply_opt,
|
|
&reply_opt_len);
|
|
/* The response of the inner message is the payload for this Relay Message Option */
|
|
inner_msg.send_buf = (void*) &reply_opt->data;
|
|
inner_msg.send_buf_maxlen -= (Ip_u16) ((Ip_ptrdiff_t) inner_msg.send_buf
|
|
- (Ip_ptrdiff_t) msg->send_buf);
|
|
|
|
/* Process the inner message */
|
|
err = ipdhcps6_process_message(&inner_msg);
|
|
if (err != IPCOM_SUCCESS)
|
|
return err;
|
|
|
|
err = ipdhcps6_option_add_relay_message(reply_opt,
|
|
reply_opt_len,
|
|
&written,
|
|
inner_msg.send_buf,
|
|
inner_msg.send_buf_len);
|
|
if (err != IP_NULL)
|
|
return err;
|
|
ipdhcps6_msg_next_response_opt(written,
|
|
msg,
|
|
&reply_opt,
|
|
&reply_opt_len);
|
|
|
|
|
|
|
|
interface_id_opt = ipdhcps6_option_get_ptr(in_opts,
|
|
in_opts_len,
|
|
IPDHCPS6_OPTION_INTERFACE_ID);
|
|
if (interface_id_opt != IP_NULL)
|
|
{
|
|
/* Copy the Interface Id Option verbatim */
|
|
written = (Ip_u16)(ipdhcps6_get_u16(&interface_id_opt->len) + IPDHCPS6_OPTION_HDR_LEN);
|
|
if (written > reply_opt_len)
|
|
{
|
|
IPCOM_LOG0(WARNING, "Could not create response since the response is too small");
|
|
return IPCOM_ERR_NO_MEMORY;
|
|
}
|
|
ipcom_memcpy(reply_opt, interface_id_opt, written);
|
|
ipdhcps6_msg_next_response_opt(written,
|
|
msg,
|
|
&reply_opt,
|
|
&reply_opt_len);
|
|
}
|
|
msg->send_response = IP_TRUE;
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 11 PUBLIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* END OF FILE
|
|
****************************************************************************
|
|
*/
|
|
|