753 lines
26 KiB
C
753 lines
26 KiB
C
/*
|
|
******************************************************************************
|
|
* INTERPEAK SOURCE FILE
|
|
*
|
|
* Document no: @(#) $Name: VXWORKS_ITER40_RCPL8_2024030303 $ $RCSfile: ipdhcps6_prefix.c,v $ $Revision: 1.25.12.2 $
|
|
* $Source: /home/interpeak/CVSRoot/ipdhcps6/src/ipdhcps6_prefix.c,v $
|
|
* $Author: jchang1 $
|
|
* $State: Exp $ $Locker: $
|
|
*
|
|
* INTERPEAK_COPYRIGHT_STRING
|
|
* Design and implementation by Kenneth Jonsson <kenneth@interpeak.se>
|
|
******************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 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_list.h>
|
|
#include <ipcom_syslog.h>
|
|
|
|
#include <ipnet.h>
|
|
#include <ipnet_routesock.h>
|
|
|
|
#include "ipdhcps6.h"
|
|
#include "ipdhcps6_h.h"
|
|
#include "ipdhcps6_host.h"
|
|
#include "ipdhcps6_prefix.h"
|
|
#include "ipdhcps6_subnet.h"
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 4 DEFINES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 5 TYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
typedef struct Ipdhcps6_prefix_list_data_struct
|
|
{
|
|
Ipdhcps6_prefix *prefix;
|
|
int index;
|
|
}
|
|
Ipdhcps6_prefix_list_data;
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 6 EXTERN PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 7 LOCAL PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 8 DATA
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 9 STATIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipdhcps6_prefix_obj_hash
|
|
*===========================================================================
|
|
* Description: Returns a hash value based on a DHCP option.
|
|
* Parameters: opt - The option to return a hash value for.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC unsigned
|
|
ipdhcps6_prefix_obj_hash(Ipdhcps6_prefix *prefix)
|
|
{
|
|
return ipcom_hash_update(prefix->key, ipcom_strlen(prefix->key), 0);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipdhcps6_prefix_key_hash
|
|
*===========================================================================
|
|
* Description: Returns a hash value for a prefix key.
|
|
* Parameters: key - The prefix ID number.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC unsigned
|
|
ipdhcps6_prefix_key_hash(char *key)
|
|
{
|
|
return ipcom_hash_update(key, ipcom_strlen(key), 0);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipdhcps6_prefix_hash_cmp
|
|
*===========================================================================
|
|
* Description: Compares a hash object and a hash key for equality.
|
|
* Parameters: prefix - A prefix structure.
|
|
* key - A pointer to the search key.
|
|
* Returns: IP_TRUE if the search key matches the prefix entry.
|
|
*
|
|
*/
|
|
IP_STATIC Ip_bool
|
|
ipdhcps6_prefix_hash_cmp(Ipdhcps6_prefix *prefix, char *key)
|
|
{
|
|
return ipcom_strcmp(prefix->key, key) == 0;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipdhcps6_prefix_free_cb
|
|
*===========================================================================
|
|
* Description: Frees the specified prefix.
|
|
* Parameters: prefix - A prefix structure.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipdhcps6_prefix_free_cb(Ipdhcps6_prefix *prefix, void *unused)
|
|
{
|
|
(void) unused;
|
|
ipcom_free(prefix);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipdhcps6_prefix_list_cb
|
|
*===========================================================================
|
|
* Description: Makes a deep copy of all prefix entries.
|
|
* Parameters: prefix - A prefix structure.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipdhcps6_prefix_list_cb(Ipdhcps6_prefix *prefix, Ipdhcps6_prefix_list_data *list_data)
|
|
{
|
|
ipcom_memcpy(&list_data->prefix[list_data->index++], prefix, sizeof(Ipdhcps6_prefix));
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipdhcps6_prefix_get_ptr
|
|
*===========================================================================
|
|
* Description: Returns the prefix entry corrensponding to the specified key.
|
|
* Parameters: key - The ID number for the prefix to return
|
|
* Returns: The matching prefix entry or IP_NULL if no match was found.
|
|
*
|
|
*/
|
|
IP_STATIC Ipdhcps6_prefix *
|
|
ipdhcps6_prefix_get_ptr(IP_CONST char *key)
|
|
{
|
|
return ipcom_hash_get(ipdhcps6->db.prefixes, (void *) key);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipdhcps6_prefix_get_ptr_from_host
|
|
*===========================================================================
|
|
* Description: Returns the prefix entry on a specific host.
|
|
* Parameters: host - The host to which this prefix must be assigned.
|
|
* prefix - The address of the prefix to find.
|
|
* prefix_len - The length of the prefix to find.
|
|
* Returns: The matching prefix entry or IP_NULL if no match was found.
|
|
*
|
|
*/
|
|
IP_STATIC Ipdhcps6_prefix *
|
|
ipdhcps6_prefix_get_ptr_from_host(Ipdhcps6_host *host,
|
|
struct Ip_in6_addr *prefix,
|
|
int prefix_len)
|
|
{
|
|
Ipdhcps6_prefix *p;
|
|
int i;
|
|
|
|
for (i = 0; i < IPDHCPS6_PREFIX_PER_USER; i++)
|
|
{
|
|
if (host->user.prefix_ids[i][0] == '\0')
|
|
continue;
|
|
p = ipdhcps6_prefix_get_ptr(host->user.prefix_ids[i]);
|
|
if (p == IP_NULL)
|
|
continue;
|
|
if (prefix_len == p->prefix_len
|
|
&& IP_IN6_ARE_ADDR_EQUAL(prefix, &p->prefix))
|
|
return p;
|
|
}
|
|
return IP_NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipdhcps6_prefix_add_del_rt
|
|
*===========================================================================
|
|
* Description: Adds/deletes a route to the prefix that is beeing handed out.
|
|
* Parameters: ifindex - The interface that have to be used to reach this prefix.
|
|
* prefix - The prefix that is beeing handed out.
|
|
* prefixlen - The prefix length.
|
|
* add - IP_TRUE if the route should be added, it will be deleted
|
|
* otherwise.
|
|
* Returns: IPCOM_SUCCESS - operation was successful.
|
|
* IPCOM_ERR_NO_MEMORY - could not allocate enough memory.
|
|
*
|
|
*/
|
|
IP_STATIC Ip_err
|
|
ipdhcps6_prefix_add_del_rt(int ifindex, struct Ip_in6_addr *prefix, int prefixlen , Ip_bool add)
|
|
{
|
|
struct Ip_sockaddr_in6 *gw;
|
|
struct Ip_sockaddr_in6 *net;
|
|
struct Ip_sockaddr_in6 *mask;
|
|
struct Ipnet_rt_msghdr *rtm = IP_NULL;
|
|
Ip_u16 rtm_len;
|
|
int rt_sock;
|
|
struct Ip_in6_ifreq ifreq6;
|
|
Ip_err err;
|
|
|
|
rt_sock = ipcom_socket(IP_AF_ROUTE, IP_SOCK_RAW, 0);
|
|
if (rt_sock == IP_INVALID_SOCKET)
|
|
{
|
|
IPCOM_LOG0(ERR, "Failed to open routing socket");
|
|
err = IPCOM_ERR_SOCKCALLFAILED;
|
|
/* Coverity defect fix for NEGATIVE_RETURNS */
|
|
return err;
|
|
}
|
|
|
|
(void)ipcom_if_indextoname((Ip_u32)ifindex, ifreq6.ifr_name);
|
|
if (ipcom_socketioctl(rt_sock, IP_SIOCGIFDSTADDR_IN6, &ifreq6) < 0)
|
|
/* Not a point-to-point interface or no peer address set, ignore t */
|
|
return IPCOM_SUCCESS;
|
|
|
|
/* Peer address present, route any packets destinated to the network defined
|
|
by the prefix to the PPP peer */
|
|
rtm_len = sizeof(struct Ipnet_rt_msghdr) + sizeof(struct Ip_sockaddr_in6) * 3;
|
|
rtm = ipcom_calloc(1, rtm_len);
|
|
if (rtm == IP_NULL)
|
|
{
|
|
IPCOM_LOG0(ERR, "Out of memory while adding route.");
|
|
err = IPCOM_ERR_NO_MEMORY;
|
|
goto cleanup;
|
|
}
|
|
|
|
net = (struct Ip_sockaddr_in6 *) (rtm + 1);
|
|
gw = (struct Ip_sockaddr_in6 *) (net + 1);
|
|
mask = (struct Ip_sockaddr_in6 *) (gw + 1);
|
|
|
|
rtm->rtm_msglen = rtm_len;
|
|
rtm->rtm_version = IPNET_RTM_VERSION;
|
|
rtm->rtm_type = (Ip_u8)(add ? IPNET_RTM_ADD : IPNET_RTM_DELETE);
|
|
rtm->rtm_index = (Ip_u32)ifindex;
|
|
rtm->rtm_flags = IPNET_RTF_UP | IPNET_RTF_GATEWAY | IPNET_RTF_DONE
|
|
| IPNET_RTF_MASK | IPNET_RTF_DYNAMIC;
|
|
rtm->rtm_addrs = IPNET_RTA_DST | IPNET_RTA_GATEWAY | IPNET_RTA_NETMASK;
|
|
rtm->rtm_pid = ipcom_getpid();
|
|
rtm->rtm_rmx.rmx_expire = IPCOM_ADDR_INFINITE;
|
|
|
|
/* Network */
|
|
IPCOM_SA_LEN_SET(net, sizeof(*net));
|
|
net->sin6_family = IP_AF_INET6;
|
|
IPDHCPS6_SET_IN6_ADDR(&net->sin6_addr, prefix);
|
|
|
|
/* Mask */
|
|
IPCOM_SA_LEN_SET(mask, sizeof(*mask));
|
|
mask->sin6_family = IP_AF_INET6;
|
|
ipdhcps6_create_mask(&mask->sin6_addr, prefixlen);
|
|
|
|
/* Gateway */
|
|
ipcom_memcpy(gw, &ifreq6.ifr_ifru.ifru_dstaddr, IPCOM_SA_LEN_GET(&ifreq6.ifr_ifru.ifru_dstaddr));
|
|
|
|
if (ipcom_send(rt_sock, rtm, rtm->rtm_msglen, 0) < 0)
|
|
{
|
|
IPCOM_LOG1(ERR, "Failed to send route socket message: %s",
|
|
ipcom_strerror(ipcom_errno));
|
|
}
|
|
err = IPCOM_SUCCESS;
|
|
|
|
cleanup:
|
|
ipcom_socketclose(rt_sock);
|
|
ipcom_free(rtm);
|
|
return err;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipdhcps6_prefix_add_del_prefixes
|
|
*===========================================================================
|
|
* Description: Adds or deletes all prefixes that this host should get.
|
|
* Parameters: subnet - The subnet the requesting router is located at.
|
|
* host - The host entry for the requesting router.
|
|
* response_opt - Buffer to where all OPTION_IAPREFIX options
|
|
* will be copied.
|
|
* response_optlen - Length of the 'response_opt' buffer.
|
|
* bytes_written - Number of bytes written to 'opt' or the requeried
|
|
* length of 'opt' if failed with IPCOM_ERR_NO_MEMORY.
|
|
* Returns: IPCOM_SUCCESS - operation was successful.
|
|
* IPCOM_ERR_NO_MEMORY - the 'response_opt' buffer was not large enough.
|
|
*
|
|
*/
|
|
IP_STATIC Ip_err
|
|
ipdhcps6_prefix_add_del_prefixes(Ipdhcps6_subnet_entry *subnet,
|
|
Ipdhcps6_host *host,
|
|
Ipdhcps6_option_iaprefix *response_opt,
|
|
Ip_u16 response_optlen,
|
|
Ip_u16 *bytes_written,
|
|
Ip_bool add)
|
|
{
|
|
Ipdhcps6_prefix *prefix;
|
|
Ip_u16 written;
|
|
Ip_err err;
|
|
int i;
|
|
|
|
(void) subnet;
|
|
*bytes_written = 0;
|
|
for (i = 0; i < IPDHCPS6_PREFIX_PER_USER; i++)
|
|
{
|
|
if (host->user.prefix_ids[i][0] == '\0')
|
|
continue;
|
|
prefix = ipdhcps6_prefix_get_ptr(host->user.prefix_ids[i]);
|
|
if (prefix == IP_NULL)
|
|
{
|
|
IPCOM_LOG2(WARNING, "Prefix %s was specified for user %s but not found in the prefix database",
|
|
host->user.prefix_ids[i], host->user.name);
|
|
continue;
|
|
}
|
|
|
|
if (add)
|
|
{
|
|
err = ipdhcps6_option_add_iaprefix(response_opt,
|
|
(Ip_u16) (response_optlen - *bytes_written),
|
|
&written,
|
|
prefix);
|
|
if (err != IPCOM_SUCCESS)
|
|
return err;
|
|
*bytes_written += written;
|
|
response_opt = (Ipdhcps6_option_iaprefix *) ((Ip_u8 *) response_opt + written);
|
|
}
|
|
err = ipdhcps6_prefix_add_del_rt(host->ifindex, &prefix->prefix, prefix->prefix_len, add);
|
|
}
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipdhcps6_prefix_renew_prefixes
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns: IPCOM_SUCCESS - operation was successful.
|
|
* IPCOM_ERR_NO_MEMORY - the 'response_opt' buffer was not large enough.
|
|
*
|
|
*/
|
|
IP_STATIC Ip_err
|
|
ipdhcps6_prefix_renew_prefixes(Ipdhcps6_subnet_entry *subnet,
|
|
Ipdhcps6_host *host,
|
|
Ipdhcps6_option *request_ia_pd_opt,
|
|
Ipdhcps6_option_iaprefix *response_opt,
|
|
Ip_u16 response_optlen,
|
|
Ip_u16 *bytes_written)
|
|
{
|
|
Ipdhcps6_prefix *prefix;
|
|
Ipdhcps6_option_iaprefix *response_ptr;
|
|
Ipdhcps6_option_iaprefix *request_ptr;
|
|
Ipdhcps6_option_iaprefix iaprefix;
|
|
const Ip_u16 iaprefix_len = 25;
|
|
Ip_u16 id_pd_opt_len;
|
|
Ip_u16 request_offset;
|
|
Ip_u16 request_iaprefix_len;
|
|
|
|
(void)subnet;
|
|
id_pd_opt_len = (Ip_u16) (ipdhcps6_get_u16(&request_ia_pd_opt->len)
|
|
- ip_offsetof(struct Ipdhcps6_option_prefix_delegation_data, options)
|
|
- IPDHCPS6_OPTION_HDR_LEN);
|
|
|
|
ipcom_memset(&prefix, 0, sizeof(prefix));
|
|
|
|
ipdhcps6_set_u16(&iaprefix.code, IPDHCPS6_OPTION_IAPREFIX);
|
|
ipdhcps6_set_u16(&iaprefix.len, iaprefix_len);
|
|
*bytes_written = 0;
|
|
for (request_offset = 0; request_offset < id_pd_opt_len;)
|
|
{
|
|
/* Point to the IAPREFIX option to process in the reqeust */
|
|
request_ptr = (Ipdhcps6_option_iaprefix *)
|
|
((Ip_u8 *) request_ia_pd_opt->data.ia_pd.options + request_offset);
|
|
|
|
if (response_optlen < *bytes_written + iaprefix_len + IPDHCPS6_OPTION_HDR_LEN)
|
|
/* The OPTION_IAPREFIX does not fit into the response buffer */
|
|
return IPCOM_ERR_NO_MEMORY;
|
|
|
|
ipcom_memcpy(IPDHCPS6_OPTION_IAPREFIX_GET_PREFIX_PTR(&iaprefix),
|
|
IPDHCPS6_OPTION_IAPREFIX_GET_PREFIX_PTR(request_ptr),
|
|
sizeof(struct Ip_in6_addr));
|
|
IPDHCPS6_OPTION_IAPREFIX_SET_LEN(&iaprefix, IPDHCPS6_OPTION_IAPREFIX_GET_LEN(request_ptr));
|
|
|
|
prefix = ipdhcps6_prefix_get_ptr_from_host(host,
|
|
IPDHCPS6_OPTION_IAPREFIX_GET_PREFIX_PTR(&iaprefix),
|
|
IPDHCPS6_OPTION_IAPREFIX_GET_LEN(&iaprefix));
|
|
if (prefix == IP_NULL)
|
|
{
|
|
/* This prefix is no longer used by the subnet */
|
|
iaprefix.preferred_lifetime = 0;
|
|
iaprefix.valid_lifetime = 0;
|
|
}
|
|
else
|
|
{
|
|
/* Extend the lifetime another period */
|
|
ipdhcps6_set_u32(&iaprefix.preferred_lifetime, prefix->preferred);
|
|
ipdhcps6_set_u32(&iaprefix.valid_lifetime, prefix->valid);
|
|
}
|
|
|
|
/* Point to where the this IAPREFIX should be written into the response buffer */
|
|
response_ptr = (Ipdhcps6_option_iaprefix *) ((Ip_u8 *) response_opt + *bytes_written);
|
|
/* Add the option to the response */
|
|
ipcom_memcpy(response_ptr, &iaprefix, iaprefix_len + IPDHCPS6_OPTION_HDR_LEN);
|
|
*bytes_written += iaprefix_len + IPDHCPS6_OPTION_HDR_LEN;
|
|
|
|
/* Move to the next IAPREFIX in the reqeust buffer */
|
|
request_iaprefix_len = ipdhcps6_get_u16(&request_ptr->len);
|
|
request_offset += request_iaprefix_len + IPDHCPS6_OPTION_HDR_LEN;
|
|
}
|
|
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 10 GLOBAL FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipdhcps6_prefix_process_request
|
|
*===========================================================================
|
|
* Description: Adds prefix to the requesting router (using OPTION_IA_PD).
|
|
* Parameters: msg - The message type in the request.
|
|
* host - The entry for the requesting router.
|
|
* opt - The OPTION_IA_PD option sent by the requesting router.
|
|
* response_opt - Pointer into the response buffer where the
|
|
* OPTION_IA_PD options containing the prefixes should be written.
|
|
* response_optlen - The length of the 'reponse_opt'
|
|
* bytes_written - Number of bytes written to 'opt' or the requeried
|
|
* length of 'opt' if failed with IPCOM_ERR_NO_MEMORY.
|
|
* Returns: IPCOM_SUCCESS - operation was successful.
|
|
* IPCOM_ERR_NO_MEMORY - the 'response_opt'. was to small.
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipdhcps6_prefix_process_request(Ip_u16 msg_type,
|
|
Ipdhcps6_subnet_entry *subnet,
|
|
Ipdhcps6_host *host,
|
|
Ipdhcps6_option *opt,
|
|
Ipdhcps6_option *response_opt,
|
|
Ip_u16 response_optlen,
|
|
Ip_u16 *bytes_written)
|
|
{
|
|
Ip_u16 ia_pd_opt_len;
|
|
Ipdhcps6_option_iaprefix *iaprefix;
|
|
Ip_err err;
|
|
Ip_u16 hdr_len;
|
|
|
|
*bytes_written = 0;
|
|
ia_pd_opt_len = ipdhcps6_get_u16(&opt->len);
|
|
hdr_len = ip_offsetof(struct Ipdhcps6_option_prefix_delegation_data, options);
|
|
if (ia_pd_opt_len != hdr_len)
|
|
{
|
|
if (ia_pd_opt_len < hdr_len
|
|
|| ipdhcps6_option_check((Ipdhcps6_option *) opt->data.ia_pd.options,
|
|
(Ip_u16) (ia_pd_opt_len - hdr_len)))
|
|
{
|
|
/* Error in length field in the OPTION_IA_PD option, drop the message */
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
}
|
|
|
|
if (subnet == IP_NULL)
|
|
{
|
|
/* No configuration for the subnet the requesting router is located at */
|
|
return ipdhcps6_option_add_status_code(response_opt, response_optlen,
|
|
bytes_written, IPDHCPS6_CODE_NO_PREFIX_AVAIL,
|
|
"No configuration create for the subnet from where the request originates.");
|
|
}
|
|
|
|
if (ipdhcps6_host_has_prefix(host) == IP_FALSE)
|
|
{
|
|
return ipdhcps6_option_add_status_code(response_opt, response_optlen,
|
|
bytes_written, IPDHCPS6_CODE_NO_PREFIX_AVAIL,
|
|
"The host has not been given any prefixes.");
|
|
}
|
|
|
|
ia_pd_opt_len = ip_offsetof(struct Ipdhcps6_option_prefix_delegation_data, options);
|
|
if (response_optlen < ia_pd_opt_len + IPDHCPS6_OPTION_HDR_LEN)
|
|
/* Not the response buffer is not big enough to hold the IPDHCPS6_OPTION_IA_PD header */
|
|
return IPCOM_ERR_NO_MEMORY;
|
|
|
|
/* Add the IPDHCPS6_OPTION_IA_PD header */
|
|
ipdhcps6_set_u16(&response_opt->code, IPDHCPS6_OPTION_IA_PD);
|
|
ipcom_memcpy(&response_opt->data.ia_pd.iaid, opt->data.ia_pd.iaid, sizeof(response_opt->data.ia_pd.iaid));
|
|
/* Let the client calculate the T1 and T2 times */
|
|
ipdhcps6_set_u32(&response_opt->data.ia_pd.t1, 0);
|
|
ipdhcps6_set_u32(&response_opt->data.ia_pd.t2, 0);
|
|
response_optlen -= ia_pd_opt_len + IPDHCPS6_OPTION_HDR_LEN;
|
|
|
|
/* Pointer to where the first IPDHCPS6_OPTION_IAPREFIX should be written */
|
|
iaprefix = response_opt->data.ia_pd.options;
|
|
|
|
switch (msg_type)
|
|
{
|
|
case IPDHCPS6_MSG_SOLICIT:
|
|
case IPDHCPS6_MSG_REQUEST:
|
|
err = ipdhcps6_prefix_add_del_prefixes(subnet, host, iaprefix, response_optlen, bytes_written, IP_TRUE);
|
|
break;
|
|
case IPDHCPS6_MSG_RELEASE:
|
|
err = ipdhcps6_prefix_add_del_prefixes(subnet, host, iaprefix, response_optlen, bytes_written, IP_FALSE);
|
|
break;
|
|
case IPDHCPS6_MSG_RENEW:
|
|
case IPDHCPS6_MSG_REBIND:
|
|
err = ipdhcps6_prefix_renew_prefixes(subnet, host, opt, iaprefix, response_optlen, bytes_written);
|
|
break;
|
|
default:
|
|
/* This message type should not forward here */
|
|
return IPCOM_ERR_INVALID_ARG;
|
|
}
|
|
|
|
*bytes_written += ia_pd_opt_len;
|
|
ipdhcps6_set_u16(&response_opt->len, *bytes_written);
|
|
*bytes_written += IPDHCPS6_OPTION_HDR_LEN;
|
|
return err;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipdhcps6_prefix_new_db
|
|
*===========================================================================
|
|
* Description: Deletes all elements in the subnet database, memory for
|
|
* the route table holding the entries is also deleted.
|
|
* Parameters: subnets - The subnet database to delete.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ipcom_hash *
|
|
ipdhcps6_prefix_new_db(void)
|
|
{
|
|
return ipcom_hash_new((Ipcom_hash_obj_func) ipdhcps6_prefix_obj_hash,
|
|
(Ipcom_hash_key_func) ipdhcps6_prefix_key_hash,
|
|
(Ipcom_hash_cmp_func) ipdhcps6_prefix_hash_cmp);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipdhcps6_prefix_delete_db
|
|
*===========================================================================
|
|
* Description: Frees all prefix entries in the list.
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipdhcps6_prefix_delete_db(Ipcom_hash *prefix_db)
|
|
{
|
|
if(prefix_db != IP_NULL)
|
|
{
|
|
ipcom_hash_for_each(prefix_db,
|
|
(Ipcom_hash_foreach_cb_func) ipdhcps6_prefix_free_cb,
|
|
IP_NULL);
|
|
ipcom_hash_delete(prefix_db);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 11 PUBLIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipdhcps6_prefix_add
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_PUBLIC Ip_err
|
|
ipdhcps6_prefix_add(Ipdhcps6_prefix *prefix)
|
|
{
|
|
Ipdhcps6_prefix *p = IP_NULL;
|
|
Ip_err err;
|
|
|
|
if (ipdhcps6 == IP_NULL || IP_BIT_ISFALSE(ipdhcps6->flags, IPDHCPS6_FLAG_OPEN))
|
|
return IPCOM_ERR_NOT_OPENED;
|
|
|
|
ipcom_mutex_lock(ipdhcps6->db.mutex);
|
|
|
|
if (ipdhcps6_prefix_get_ptr(prefix->key) != IP_NULL)
|
|
{
|
|
err = IPCOM_ERR_DUPLICATE;
|
|
goto errout;
|
|
}
|
|
|
|
p = ipcom_malloc(sizeof(Ipdhcps6_prefix));
|
|
if (p == IP_NULL)
|
|
{
|
|
err = IPCOM_ERR_NO_MEMORY;
|
|
goto errout;
|
|
}
|
|
|
|
ipcom_memcpy(p, prefix, sizeof(Ipdhcps6_prefix));
|
|
if ((err = ipcom_hash_add(ipdhcps6->db.prefixes, p)) != IPCOM_SUCCESS)
|
|
goto errout;
|
|
|
|
ipcom_mutex_unlock(ipdhcps6->db.mutex);
|
|
return IPCOM_SUCCESS;
|
|
|
|
errout:
|
|
ipcom_free(p);
|
|
ipcom_mutex_unlock(ipdhcps6->db.mutex);
|
|
return err;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipdhcps6_subnet_delete
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_PUBLIC Ip_err
|
|
ipdhcps6_prefix_delete(Ipdhcps6_prefix *prefix)
|
|
{
|
|
Ipdhcps6_prefix *p;
|
|
Ip_err err = IPCOM_SUCCESS;
|
|
|
|
if (ipdhcps6 == IP_NULL || IP_BIT_ISFALSE(ipdhcps6->flags, IPDHCPS6_FLAG_OPEN))
|
|
return IPCOM_ERR_NOT_OPENED;
|
|
|
|
ipcom_mutex_lock(ipdhcps6->db.mutex);
|
|
|
|
if ((p = ipdhcps6_prefix_get_ptr(prefix->key)) == IP_NULL)
|
|
{
|
|
err = IPCOM_ERR_NOT_FOUND;
|
|
goto cleanup;
|
|
}
|
|
|
|
(void) ipcom_hash_remove(ipdhcps6->db.prefixes, p);
|
|
ipcom_free(p);
|
|
|
|
cleanup:
|
|
ipcom_mutex_unlock(ipdhcps6->db.mutex);
|
|
return err;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipdhcps6_subnet_list
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_PUBLIC Ip_err
|
|
ipdhcps6_prefix_list(Ipdhcps6_prefix prefix[], int *num_elem)
|
|
{
|
|
Ipdhcps6_prefix_list_data cb_data;
|
|
|
|
if (ipdhcps6 == IP_NULL || IP_BIT_ISFALSE(ipdhcps6->flags, IPDHCPS6_FLAG_OPEN))
|
|
return IPCOM_ERR_NOT_OPENED;
|
|
|
|
ipcom_mutex_lock(ipdhcps6->db.mutex);
|
|
|
|
if (prefix == IP_NULL)
|
|
{
|
|
*num_elem = (int)ipdhcps6->db.prefixes->elem;
|
|
ipcom_mutex_unlock(ipdhcps6->db.mutex);
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
if (*num_elem < (int) ipdhcps6->db.prefixes->elem)
|
|
{
|
|
ipcom_mutex_unlock(ipdhcps6->db.mutex);
|
|
return IPCOM_ERR_NO_MEMORY;
|
|
}
|
|
|
|
*num_elem = (int)ipdhcps6->db.prefixes->elem;
|
|
|
|
cb_data.prefix = prefix;
|
|
cb_data.index = 0;
|
|
ipcom_hash_for_each(ipdhcps6->db.prefixes,
|
|
(Ipcom_hash_foreach_cb_func) ipdhcps6_prefix_list_cb,
|
|
&cb_data);
|
|
|
|
ipcom_mutex_unlock(ipdhcps6->db.mutex);
|
|
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* END OF FILE
|
|
****************************************************************************
|
|
*/
|
|
|