Files
m241Neelima/components/ip_net2-6.9/ipdhcpc6/src/ipdhcpc6_if.c
T
2026-07-30 11:19:44 +05:30

1870 lines
59 KiB
C

/*
******************************************************************************
* INTERPEAK SOURCE FILE
*
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipdhcpc6_if.c,v $ $Revision: 1.29.12.5 $
* $Source: /home/interpeak/CVSRoot/ipdhcpc6/src/ipdhcpc6_if.c,v $
* $Author: anonymous $
* $State: Exp $ $Locker: $
*
* INTERPEAK_COPYRIGHT_STRING
* Design and implementation by Joel Hortelius <joel.hortelis@interpeak.se>
******************************************************************************
*/
/*
****************************************************************************
* 1 DESCRIPTION
****************************************************************************
*/
/*
****************************************************************************
* 2 CONFIGURATION
****************************************************************************
*/
#include "ipdhcpc6_config.h"
/*
****************************************************************************
* 3 INCLUDE FILES
****************************************************************************
*/
#define IPCOM_USE_CLIB_PROTO
#include <ipcom_clib.h>
#include <ipcom_sock.h>
#include <ipcom_sock6.h>
#include <ipcom_syslog.h>
#include <ipcom_err.h>
#include <ipcom_tmo2.h>
#include <ipcom_list.h>
#include <ipcom_time.h>
#include <ipcom_sock2.h>
#include <ipcom_hash.h>
#include <ipnet_routesock.h>
#include <ipcom_sysctl.h>
#include "ipdhcpc6.h"
#include "ipdhcpc6_h.h"
#include "ipdhcpc6_msg.h"
#include "ipdhcpc6_if.h"
#include "ipdhcpc6_info.h"
#include "ipdhcpc6_ia.h"
#include "ipdhcpc6_ia_na.h"
#include "ipdhcpc6_attr.h"
#include "ipdhcpc6_rtadv.h"
#include "ipdhcpc6_sock.h"
#include "ipdhcpc6_rtsock.h"
/*
****************************************************************************
* 4 DEFINES
****************************************************************************
*/
/*
****************************************************************************
* 5 TYPES
****************************************************************************
*/
/*
****************************************************************************
* 6 EXTERN PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 7 LOCAL PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 8 DATA
****************************************************************************
*/
/*
****************************************************************************
* 9 STATIC FUNCTIONS
****************************************************************************
*/
IP_STATIC unsigned
ipdhcpc6_ifp_obj_hash(Ipdhcpc6_if_t *ifp)
{
return ipcom_hash_update(ifp->ifname, (int)ipcom_strlen(ifp->ifname), 0);
}
IP_STATIC unsigned
ipdhcpc6_ifp_key_hash(char *ifname)
{
return ipcom_hash_update(ifname, (int)ipcom_strlen(ifname), 0);
}
IP_STATIC Ip_bool
ipdhcpc6_ifp_cmp(Ipdhcpc6_if_t *ifp, char *ifname)
{
return ipcom_strcmp(ifp->ifname, ifname) == 0;
}
/*
*===========================================================================
* ipdhcpc6_if_unset_context
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC void
ipdhcpc6_if_unset_context(Ipdhcpc6_if_t *ifp)
{
/* Remove the context if its set */
if (ifp->context)
{
ipcom_hash_remove(ifp->context->ifp_hash, ifp);
ipcom_list_remove(&ifp->next);
ifp->context = IP_NULL;
}
}
/*
*===========================================================================
* ipdhcpc6_if_server_remain
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_u32
ipdhcpc6_if_server_remain(Ipdhcpc6_if_server_t *srv)
{
if (srv->ifp->conf.info_refresh == IPDHCPC6_MODE_ENABLED &&
srv->attr->info_refresh != 0xffffffff)
{
Ip_time_t curtime = ipcom_time(0);
Ip_u32 elapsed = (Ip_u32)(curtime - srv->attr->timestamp);
Ip_u32 remain = 0;
/**/
if (elapsed < srv->attr->info_refresh)
remain = srv->attr->info_refresh - elapsed;
return IP_MIN(IPDHCPC6_MSG_IRT_DEFAULT, remain);
}
return 0xffffffff;
}
/*
*===========================================================================
* ipdhcpc6_if_server_timeout
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_bool
ipdhcpc6_if_server_timeout(Ipdhcpc6_if_server_t *srv)
{
if (ipdhcpc6_if_server_remain(srv) == 0)
{
/**/
ipdhcpc6_if_inforeq_start(srv->ifp);
}
else
{
/**/
ipdhcpc6_if_server_restart(srv->ifp->context, srv);
}
return IP_FALSE;
}
/*
*===========================================================================
* ipdhcpc6_if_set_context
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_bool
ipdhcpc6_if_set_context(Ipdhcpc6_if_t *ifp,
Ipdhcpc6_if_context_t *ifctx)
{
ipdhcpc6_if_unset_context(ifp);
/* Add it to the context hash table */
if (ipcom_hash_add(ifctx->ifp_hash, ifp) != IPCOM_SUCCESS)
{
IPCOM_LOG2(ERR,
"%s: Failed to add IFP %s to context.",
ifctx->context->name,
ifp->ifname);
return IP_FALSE;
}
/* Insert it into linked list */
ipcom_list_insert_last(&ifctx->ifp_head, &ifp->next);
ifp->context = ifctx;
return IP_TRUE;
}
/*
*===========================================================================
* ipdhcpc6_if_free
*===========================================================================
* Description: Free an interface structure
* Parameters: ifpp - [IN/OUT]. Structure that will be freed. Pointer will
* be set to NULL.
* Returns:
*
*/
IP_STATIC void
ipdhcpc6_if_free(Ipdhcpc6_if_t **ifpp)
{
Ipdhcpc6_if_t *ifp = *ifpp;
/* If set */
if (ifp)
{
/* Free the IAps */
ipdhcpc6_ia_list_free(&ifp->ia_head);
/* Clear any router advertisements and prefixes */
ipdhcpc6_rtadv_down(ifp->context->context, ifp);
/* */
ipcom_tmo2_cancel(&ifp->intr);
/**/
ipdhcpc6_msg_transaction_dereference(&ifp->inforef);
/* Remove it from the context */
ipdhcpc6_if_unset_context(ifp);
/*Free fqdn configuration*/
if (ifp->conf.fqdn.data)
{
ipdhcpc6_util_free(&ifp->conf.fqdn.data->head);
ipdhcpc6_util_free(&ifp->conf.fqdn.data);
}
/* Free and reset. */
ipdhcpc6_util_free(&ifp);
}
*ifpp = IP_NULL;
}
/*
*===========================================================================
* ipdhcpc6_if_alloc
*===========================================================================
* Description: Allocate an interface structure
* Parameters: context - The DHCPC6 context
* name - The name of the interface
* Returns: A pointer to the allocated interface structure if successful.
*
*/
IP_STATIC Ipdhcpc6_if_t *
ipdhcpc6_if_alloc(Ipdhcpc6_if_context_t *context,
const char *name)
{
Ipdhcpc6_if_t *ifp;
/* Already exists? */
if (ipcom_hash_get(context->ifp_hash, (void *)name))
{
IPCOM_LOG2(ERR,
"%s: IFP %s already exists in the provided context",
context->context->name,
name);
return IP_NULL;
}
ifp = ipcom_calloc(1, sizeof(*ifp));
if (ifp)
{
/* Store the base values */
ipcom_strncpy(ifp->ifname, name, sizeof(ifp->ifname));
/* Transaction init */
ipcom_list_init(&ifp->transactions);
ipcom_list_init(&ifp->servers);
ipcom_list_init(&ifp->rtadv.prefixes);
IPCOM_TMO2_INIT(&ifp->rtadv.timeout);
IPCOM_TMO2_INIT(&ifp->intr);
/**/
ifp->automatic.runtime.managed = IPDHCPC6_MODE_DISABLED;
ifp->automatic.runtime.other = IPDHCPC6_MODE_DISABLED;
ifp->runtime.managed = IPDHCPC6_MODE_DISABLED;
ifp->runtime.other = IPDHCPC6_MODE_DISABLED;
ifp->ia_head = ipdhcpc6_ia_list_alloc();
if (ifp->ia_head == IP_NULL)
{
IPCOM_LOG2(ERR,
"%s: IFP %s failed to allocate IA LIST",
context->context->name,
name);
ipdhcpc6_if_free(&ifp);
return IP_NULL;
}
/* Set the appropriate context */
if (ipdhcpc6_if_set_context(ifp, context) == IP_FALSE)
{
IPCOM_LOG2(ERR,
"%s: IFP %s failed to set context",
context->context->name,
name);
ipdhcpc6_if_free(&ifp);
return IP_NULL;
}
}
return ifp;
}
/*
*===========================================================================
* ipdhcpc6_if_state
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_u32
ipdhcpc6_if_state(Ipdhcpc6_if_t *ifp)
{
struct Ip_ifreq ifreq;
int ret;
/* Try resolve name to ifindex */
if (ipdhcpc6_if_nametoindex(ifp->ifname, ifp->vr) == 0)
return IPDHCPC6_IF_STATE_DETACHED;
/* Do down & destroy */
ipcom_strcpy(ifreq.ifr_name, ifp->ifname);
/* Get flags */
ret = ipdhcpc6_util_ioctl(IP_SIOCGIFFLAGS, &ifreq, ifp->vr);
/* Did I fail to retrieve the IFF flags? */
if (ret < 0)
return IPDHCPC6_IF_STATE_DETACHED;
/* Is it up and running? */
if ((ifreq.ifr_ifru.ifru_flags & (IP_IFF_UP|IP_IFF_RUNNING)) == ((IP_IFF_UP|IP_IFF_RUNNING)))
return IPDHCPC6_IF_STATE_UP;
/* Interface is down */
return IPDHCPC6_IF_STATE_DOWN;
}
/*
*===========================================================================
* ipdhcpc6_ia_na_bound_release_callback
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC void
ipdhcpc6_if_inforeq_reply(Ipdhcpc6_msg_reference_t *ref,
int event,
void *cookie)
{
/**/
switch (event)
{
case IPDHCPC6_MSG_EVENT_INFOREQ_REPLY:
ipdhcpc6_msg_transaction_invalidate(ref->transaction);
break;
}
}
/*
*===========================================================================
* ipdhcpc6_if_state_up
*===========================================================================
* Description: The interface's up
* Parameters: ifp - The interface
* Returns:
*
*/
IP_STATIC void
ipdhcpc6_if_state_event(Ipdhcpc6_if_t *ifp,
Ip_u32 ostate,
Ip_u32 nstate)
{
Ipcom_hash *htable = ipdhcpc6_msg_transaction_table_create();
int i;
/* Go through all IA's, and see if anyone requires any transactions */
for (i = 0; i < IPDHCPC6_IA_TYPE_MAX; i++)
{
Ipdhcpc6_ia_t *ia;
ia = IPCOM_LIST_FIRST(&ifp->ia_head[i]);
while (ia)
{
ia->table->ifevent(ia, htable, ostate, nstate);
ia = IPCOM_LIST_NEXT(&ia->next);
}
}
if (ifp->inforeq_required)
{
Ipdhcpc6_msg_transaction_t *trans;
if (ifp->runtime.other == IPDHCPC6_MODE_ENABLED)
{
if (ipdhcpc6_msg_transaction_reference_invalid(&ifp->inforef))
{
/**/
ifp->inforef.callback = ipdhcpc6_if_inforeq_reply;
/* INFOREQ */
trans = ipdhcpc6_msg_inforeq_create(ifp->context->context,
&ifp->inforef,
ifp);
if (trans)
ipdhcpc6_msg_transaction_start(trans);
}
}
ifp->inforeq_required = IP_FALSE;
}
/* Go through the transaction array and see if there's any we should send */
ipdhcpc6_msg_transaction_table_commit(ifp->context->context, htable);
/* Free the transaction array */
ipdhcpc6_msg_transaction_table_free(&htable);
}
/*
*===========================================================================
* ipdhcpc6_if_run_transactions
*===========================================================================
* Description: Run transactions
* Parameters: ifp - The interface.
* Returns:
*
*/
IP_STATIC Ip_bool
ipdhcpc6_if_run_transactions(Ipdhcpc6_if_t *ifp)
{
ipdhcpc6_if_state_event(ifp, ifp->state, ifp->state);
return IP_FALSE;
}
/*
*===========================================================================
* ipdhcpc6_if_server_lock
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC void
ipdhcpc6_if_server_lock(Ipdhcpc6_if_server_t *server)
{
if (server->locked == IP_FALSE)
{
server->locked = IP_TRUE;
ipdhcpc6_if_server_reference(server);
}
}
/*
*===========================================================================
* ipdhcpc6_if_server_unlock
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC void
ipdhcpc6_if_server_unlock(Ipdhcpc6_if_server_t **serverp)
{
if ((*serverp)->locked == IP_TRUE)
{
(*serverp)->locked = IP_FALSE;
ipdhcpc6_if_server_dereference(serverp);
}
}
/*
****************************************************************************
* 10 GLOBAL FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipdhcpc6_if_lookup_by_name
*===========================================================================
* Description: Lookup an interface based on name
* Parameters: context - The DHCPv6 context
* name - The interface name
* Returns: Pointer to the interface if found, IP_NULL otherwise.
*
*/
IP_GLOBAL Ipdhcpc6_if_t *
ipdhcpc6_if_lookup_by_name(Ipdhcpc6_context_t *context,
const char *name)
{
/* Already exists? */
return (Ipdhcpc6_if_t *)ipcom_hash_get(context->ifctx->ifp_hash, (void *)name);
}
/*
*===========================================================================
* ipdhcpc6_if_context_alloc
*===========================================================================
* Description: Allocate an IF context.
* Parameters: context - DHCPC6 context.
* Returns: A context if successful.
*
*/
IP_GLOBAL Ipdhcpc6_if_context_t *
ipdhcpc6_if_context_alloc(Ipdhcpc6_context_t *context)
{
Ipdhcpc6_if_context_t *ifctx = ipcom_calloc(1, sizeof(*ifctx));
if (ifctx)
{
ifctx->context = context;
/* Initialize the IFP head */
ipcom_list_init(&ifctx->ifp_head);
/* Create the required HASH'es */
ifctx->ifp_hash = ipcom_hash_new((Ipcom_hash_obj_func) ipdhcpc6_ifp_obj_hash,
(Ipcom_hash_key_func) ipdhcpc6_ifp_key_hash,
(Ipcom_hash_cmp_func) ipdhcpc6_ifp_cmp);
if (ifctx->ifp_hash == IP_NULL)
goto errout;
ifctx->ia_hash = ipdhcpc6_ia_hash_alloc();
if (ifctx->ia_hash == IP_NULL)
goto errout;
ipdhcpc6_util_buffer_init(&ifctx->duid);
return ifctx;
errout:
if (ifctx->ifp_hash != IP_NULL)
ipcom_hash_delete(ifctx->ifp_hash);
ipdhcpc6_ia_hash_free(&ifctx->ia_hash);
return IP_NULL;
}
return ifctx;
}
/*
*===========================================================================
* ipdhcpc6_if_context_free
*===========================================================================
* Description: Free an IF context.
* Parameters: contextp - [IN/OUT] IF context to free. contextp will be set to
* IP_NULL
* Returns:
*
*/
IP_GLOBAL void
ipdhcpc6_if_context_free(Ipdhcpc6_if_context_t **contextp)
{
Ipdhcpc6_if_context_t *ifctx = *contextp;
if (ifctx)
{
Ipdhcpc6_if_t *ifp;
while ((ifp = IPCOM_LIST_FIRST(&ifctx->ifp_head)) != IP_NULL)
ipdhcpc6_if_free(&ifp);
ipcom_hash_delete(ifctx->ifp_hash);
/* Free the IA hashes */
ipdhcpc6_ia_hash_free(&ifctx->ia_hash);
ipdhcpc6_util_buffer_release(&ifctx->duid);
}
*contextp = IP_NULL;
}
/*
*===========================================================================
* ipdhcpc6_if_context_update
*===========================================================================
* Description: Goes through the interface context and initializes
* all interface entries.
* Parameters: ifctx - A interface context
* vr_index - VR index
* Returns:
*
*/
IP_GLOBAL void
ipdhcpc6_if_context_update(Ipdhcpc6_if_context_t *ifctx, int vr_index)
{
Ipdhcpc6_if_t *ifp;
ip_assert(IP_NULL != ifctx);
ifp = IPCOM_LIST_FIRST(&ifctx->ifp_head);
while (ifp != IP_NULL)
{
if (IPCOM_VR_ANY == vr_index || vr_index == ifp->vr)
ipdhcpc6_if_update_state(ifp);
ifp = IPCOM_LIST_NEXT(&ifp->next);
}
}
/*
*===========================================================================
* ipdhcpc6_if_configure
*===========================================================================
* Description: Create and configure an interface.
* Parameters: ifctx - The interface context.
* ifname - The name of the interface.
* mode - Enabled/Disabled/Automatic
* Returns: IP_TRUE if successful.
*
*/
IP_GLOBAL Ip_bool
ipdhcpc6_if_configure(Ipdhcpc6_if_context_t *ifctx,
const char *ifname,
int mode)
{
Ipdhcpc6_if_t *ifp = ipdhcpc6_if_alloc(ifctx, ifname);
Ip_u8 flags;
char hostName[255];
if (ifp)
{
/* Got the IFP */
ifp->mode = (Ip_u32)mode;
/* if get vr value automatically, we must try to listen NEWVR event
* becasue we need change the vr information on the 'ifp',
* e.g. vr change from 1 -> 0 -> 1
* and the result is we must create IPCOM_VR_MAX sockets to listen
* the NEWVR event, whatever all is a little ugly */
ifp->vr = ipdhcpc6_util_sysvar_int(0,
IPDHCPC6_NAME ".if.%s.vr",
ifname);
ipdhcpc6_nlsock_create(ifctx->context->rtctx, ifp->vr);
ipdhcpc6_sock_create(ifctx->context->sctx, ifp->vr);
ipdhcpc6_rtadv_sock_create(ifctx->context->rtadvctx, ifp->vr);
/* Read the basic values */
ifp->conf.information_only = (Ip_u32)ipdhcpc6_util_sysvar_bool(IP_FALSE,
IPDHCPC6_NAME ".if.%s.information_only",
ifname);
ifp->conf.rapid_commit = (Ip_u32)ipdhcpc6_util_sysvar_bool(IP_FALSE,
IPDHCPC6_NAME ".if.%s.rapid_commit",
ifname);
ifp->conf.dns = (Ip_u32)ipdhcpc6_util_sysvar_bool(IP_FALSE,
IPDHCPC6_NAME ".if.%s.dns",
ifname);
ifp->conf.sntp = (Ip_u32)ipdhcpc6_util_sysvar_bool(IP_FALSE,
IPDHCPC6_NAME ".if.%s.sntp",
ifname);
ifp->conf.info_refresh = (Ip_u32)ipdhcpc6_util_sysvar_bool(IP_FALSE,
IPDHCPC6_NAME ".if.%s.information_refresh",
ifname);
ifp->conf.sip = (Ip_u32)ipdhcpc6_util_sysvar_bool(IP_FALSE,
IPDHCPC6_NAME ".if.%s.sip",
ifname);
ifp->conf.vendor_spec_info = (Ip_u32)ipdhcpc6_util_sysvar_bool(IP_FALSE,
IPDHCPC6_NAME ".if.%s.vendor_spec.info",
ifname);
/*Read fqdn configuration*/
ifp->conf.fqdn.fqdn = (Ip_u32)ipdhcpc6_util_sysvar_bool(IPDHCPC6_MODE_DISABLED,
IPDHCPC6_NAME ".if.%s.fqdn.fqdn",
ifname);
ifp->conf.fqdn.update = (Ip_u32)ipdhcpc6_util_sysvar_bool(IPDHCPC6_MODE_DISABLED,
IPDHCPC6_NAME ".if.%s.fqdn.update",
ifname);
ifp->conf.fqdn.request = (Ip_u32)ipdhcpc6_util_sysvar_bool(IPDHCPC6_MODE_ENABLED,
IPDHCPC6_NAME ".if.%s.fqdn.request",
ifname);
if (ifp->conf.fqdn.fqdn == IPDHCPC6_MODE_ENABLED)
{
ipcom_memset (hostName, 0, sizeof(hostName));
ipcom_memset (&flags, 0, sizeof(flags));
/*Create the buffer for storing the fqdn*/
if (ifp->conf.fqdn.data == IP_NULL)
ifp->conf.fqdn.data = ipcom_calloc(1, sizeof(*(ifp->conf.fqdn.data)));
if (ifp->conf.fqdn.data)
{
Ip_u8 dc_len;
char *dc_len_ptr;
char *payload;
ifp->conf.fqdn.data->offset = 0;
/*set 'S' to 1*/
if (ifp->conf.fqdn.update != IPDHCPC6_MODE_ENABLED)
IP_BIT_SET (flags, IPDHCPC6_FQDN_FLAG_S);
/*Flags of the fqdn*/
ipdhcpc6_util_buffer_append(ifp->conf.fqdn.data, &flags, sizeof(Ip_u8));
/*not \0 is OK*/
hostName[0]='x';
ipcom_gethostname(hostName+1, sizeof(hostName));
/*Domain-name format------[length(one byte)+name] max255*/
flags = ipcom_strlen(hostName)+1;
/*Here flags mean the length of domain name*/
payload = hostName;
do
{
dc_len = 0;
dc_len_ptr = payload++;
while (*payload != '.' && *payload != '\0')
{
++dc_len;
++payload;
}
*dc_len_ptr = dc_len;
}while (*payload != '\0');
ipdhcpc6_util_buffer_append(ifp->conf.fqdn.data, hostName, flags);
}
else
{
/*No buffer avaiable, disable fqdn option*/
ifp->conf.fqdn.fqdn = IPDHCPC6_MODE_DISABLED;
IPCOM_LOG0 (WARNING, "no buffer for fqdn configuration,disable it");
}
}
ifp->automatic.runtime.managed = IPDHCPC6_MODE_DISABLED;
ifp->automatic.runtime.other = IPDHCPC6_MODE_DISABLED;
if (mode == IPDHCPC6_MODE_AUTOMATIC)
{
ifp->runtime.managed = IPDHCPC6_MODE_DISABLED;
ifp->runtime.other = IPDHCPC6_MODE_DISABLED;
}
else if (mode == IPDHCPC6_MODE_ENABLED)
{
if (ifp->conf.information_only == IPDHCPC6_MODE_ENABLED)
ifp->runtime.managed = IPDHCPC6_MODE_DISABLED;
else
ifp->runtime.managed = IPDHCPC6_MODE_ENABLED;
ifp->runtime.other = IPDHCPC6_MODE_ENABLED;
}
/* Read the IA's if we're not information only */
ipdhcpc6_ia_configure(ifp);
return IP_TRUE;
}
return IP_FALSE;
}
/*
*===========================================================================
* ipdhcpc6_if_lookup_by_ifobj
*===========================================================================
* Description: Lookup an interface based on an identity block
* Parameters: context - The DHCPv6 context
* ifobj - The ifobj
* Returns: Pointer to the interface if found, IP_NULL otherwise.
*
*/
IP_GLOBAL Ipdhcpc6_if_t *
ipdhcpc6_if_lookup_by_ifobj(Ipdhcpc6_context_t *context,
Ipdhcpc6_attr_if_t *ifobj)
{
if (ifobj->ifname == IP_NULL)
return IP_NULL;
return ipdhcpc6_if_lookup_by_name(context, ifobj->ifname);
}
/*
*===========================================================================
* ipdhcpc6_if_attr_header
*===========================================================================
* Description: Add the identity attributes for an interface block.
* Parameters: ifp - Interface pointer
* buf - Buffer
* Returns:
*
*/
IP_GLOBAL void
ipdhcpc6_if_attr_header(Ipdhcpc6_if_t *ifp,
Ipdhcpc6_tagcomm_buffer_t *buf)
{
Ipdhcpc6_if_server_t *srv;
ipdhcpc6_tagcomm_add_tag(buf,
IPDHCPC6_IA_IDENT_NAME,
IPDHCPC6_TAGCOMM_STATUS_OK,
ifp->ifname,
ipcom_strlen(ifp->ifname) + 1);
ipdhcpc6_tagcomm_add_tag(buf,
IPDHCPC6_IA_ATTR_IF_MODE,
IPDHCPC6_TAGCOMM_STATUS_OK,
&ifp->mode,
sizeof(ifp->mode));
ipdhcpc6_tagcomm_add_tag(buf,
IPDHCPC6_IA_ATTR_IF_VR,
IPDHCPC6_TAGCOMM_STATUS_OK,
&ifp->vr,
sizeof(ifp->vr));
ipdhcpc6_tagcomm_add_tag(buf,
IPDHCPC6_IA_ATTR_IF_LINK_STATE,
IPDHCPC6_TAGCOMM_STATUS_OK,
&ifp->state,
sizeof(ifp->state));
srv = IPCOM_LIST_FIRST(&ifp->servers);
while (srv != IP_NULL)
{
ipdhcpc6_if_server_attr(buf, srv);
srv = IPCOM_LIST_NEXT(&srv->next);
}
}
/*
*===========================================================================
* ipdhcpc6_if_update_state
*===========================================================================
* Description: Change the state of an interface
* Parameters: ifp - The interface
* Returns:
*
*/
IP_GLOBAL void
ipdhcpc6_if_update_state(Ipdhcpc6_if_t *ifp)
{
Ip_u32 ostate = ifp->state;
Ip_u32 nstate = ipdhcpc6_if_state(ifp);
/**/
if (ostate != nstate)
{
ifp->state = nstate;
if (nstate == IPDHCPC6_IF_STATE_UP)
{
IPCOM_LOG2(DEBUG,
"current M/O flag = %d/%d.",
ifp->runtime.managed,
ifp->runtime.other);
#if 0 /* KONG verify this with "noroute" case */
/* only start if needed, this flag is related with RA flag(M=1&&O=0) */
if ((ifp->runtime.managed != IPDHCPC6_MODE_ENABLED)
&& (ifp->runtime.other == IPDHCPC6_MODE_ENABLED))
#endif
{
(void)ipcom_gettimeofday(&ifp->init_time, IP_NULL);
ipdhcpc6_if_inforeq_start(ifp);
ipdhcpc6_rtadv_up(ifp->context->context, ifp);
}
}
else if (ostate == IPDHCPC6_IF_STATE_UP)
{
Ipdhcpc6_if_server_t *server;
Ipdhcpc6_if_server_t *nserver;
server = IPCOM_LIST_FIRST(&ifp->servers);
while (server != IP_NULL)
{
nserver = IPCOM_LIST_NEXT(&server->next);
ipdhcpc6_if_server_unlock(&server);
server = nserver;
}
/**/
ifp->have_link_local = IP_FALSE;
ipdhcpc6_rtadv_down(ifp->context->context, ifp);
ipdhcpc6_if_inforeq_stop(ifp);
}
ipdhcpc6_if_state_event(ifp, ostate, nstate);
}
}
/*
*===========================================================================
* ipdhcpc6_if_server_reference
*===========================================================================
* Description: Reference the server
* Parameters: server - The server to reference
* Returns:
*
*/
IP_GLOBAL void
ipdhcpc6_if_server_reference(Ipdhcpc6_if_server_t *server)
{
server->references++;
}
/*
*===========================================================================
* ipdhcpc6_if_server_dereference
*===========================================================================
* Description: Dereference the server
* Parameters: serverp - The server to dereference
* Returns:
*
*/
IP_GLOBAL void
ipdhcpc6_if_server_dereference(Ipdhcpc6_if_server_t **serverp)
{
Ipdhcpc6_if_server_t *server = *serverp;
if (server)
{
if (--server->references == 0)
{
ipcom_list_remove(&server->next);
ipdhcpc6_info_update(server->ifp->context);
ipdhcpc6_attr_if_server_free(&server->attr);
ipcom_tmo2_cancel(&server->refresh);
ipdhcpc6_util_free(&server);
}
}
*serverp = IP_NULL;
}
/*
*===========================================================================
* ipdhcpc6_if_server_sort
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC void
ipdhcpc6_if_server_sort(Ipdhcpc6_if_t *ifp,
Ipdhcpc6_if_server_t *nserver)
{
Ipdhcpc6_if_server_t *server;
ipdhcpc6_if_schedule_transaction(ifp);
server = IPCOM_LIST_FIRST(&ifp->servers);
while (server != IP_NULL)
{
if (server->preference < nserver->preference)
{
ipcom_list_insert_before(&server->next, &nserver->next);
return;
}
server = IPCOM_LIST_NEXT(&server->next);
}
ipcom_list_insert_last(&ifp->servers, &nserver->next);
}
/*
*===========================================================================
* ipdhcpc6_if_server_lookup
*===========================================================================
* Description: Lookup a server in the interface or create it if specified.
* Parameters: ifp - The interface pointer.
* addr - Address
* sduid - Server DUID
* slen - Server DUID length
* preference - Server preference
* create - Create if not found.
* Returns: A server if successful
*
*/
IP_GLOBAL Ipdhcpc6_if_server_t *
ipdhcpc6_if_server_lookup(Ipdhcpc6_if_t *ifp,
struct Ip_in6_addr *addr,
void *sduid,
Ip_size_t slen,
Ip_u8 preference,
Ip_bool create)
{
Ipdhcpc6_if_server_t *server;
server = IPCOM_LIST_FIRST(&ifp->servers);
while (server != IP_NULL)
{
if (server->attr->id_size == slen &&
IP_IN6_ARE_ADDR_EQUAL(addr, &server->attr->address) &&
ipcom_memcmp(server->attr->id_vector, sduid, slen) == 0)
{
if (server->preference != preference)
{
server->preference = preference;
ipcom_list_remove(&server->next);
ipdhcpc6_if_server_sort(ifp, server);
}
return server;
}
server = IPCOM_LIST_NEXT(&server->next);
}
/* Not found; create new */
server = ipcom_calloc(1, sizeof(*server));
if (server)
{
server->attr = ipcom_calloc(1, sizeof(*server->attr));
if (server->attr == IP_NULL)
ipdhcpc6_util_free(&server);
else
{
server->attr->id_vector = ipcom_malloc(slen);
if (server->attr->id_vector == IP_NULL)
{
ipdhcpc6_attr_if_server_free(&server->attr);
ipdhcpc6_util_free(&server);
}
else
{
/**/
ipcom_memcpy(server->attr->id_vector, sduid, slen);
server->attr->id_size = slen;
ipcom_memcpy(&server->attr->address, addr, sizeof(*addr));
IPCOM_TMO2_INIT(&server->refresh);
server->preference = preference;
server->ifp = ifp;
server->attr->timestamp = (Ip_u32)ipcom_time(0);
server->attr->info_refresh = (Ip_u32)ipdhcpc6_util_sysvar_int(IPDHCPC6_MSG_IRT_DEFAULT,
IPDHCPC6_NAME ".if.%s.information_refresh.default",
ifp->ifname);
ipdhcpc6_if_server_sort(ifp, server);
}
}
ipdhcpc6_if_server_lock(server);
}
return server;
}
/*
*===========================================================================
* ipdhcpc6_if_rtadv_process
*===========================================================================
* Description: Update current state of interface.
* Parameters: ifp - Interface
* rtr - Router advertising the values.
* managed - Switch to managed mode
* info - Info retrieval
* Returns:
*
*/
IP_GLOBAL void
ipdhcpc6_if_rtadv_process(Ipdhcpc6_if_t *ifp,
const struct Ip_in6_addr *rtr,
Ip_bool managed,
Ip_bool info)
{
Ip_u32 mval = (Ip_u32)(managed? IPDHCPC6_MODE_ENABLED : IPDHCPC6_MODE_DISABLED);
Ip_u32 oval = (Ip_u32)(info? IPDHCPC6_MODE_ENABLED : IPDHCPC6_MODE_DISABLED);
IPCOM_LOG4(DEBUG,
"receive RA M/O flag = %d/%d; current M/O flag = %d/%d.",
ifp->automatic.runtime.managed,
ifp->automatic.runtime.other,
mval,
oval);
/* Value */
ipcom_memcpy(&ifp->automatic.rtr, rtr, sizeof(*rtr));
ifp->automatic.runtime.other = oval;
ifp->automatic.runtime.managed = mval;
if (ifp->mode == IPDHCPC6_MODE_AUTOMATIC)
{
Ip_bool mchange = IP_FALSE;
Ip_bool ochange = IP_FALSE;
/* XXX: Need to update variables depending on RTADV */
if (ifp->runtime.managed != ifp->automatic.runtime.managed)
{
ifp->runtime.managed = ifp->automatic.runtime.managed;
mchange = IP_TRUE;
}
if (ifp->runtime.other != ifp->automatic.runtime.other)
{
ifp->runtime.other = ifp->automatic.runtime.other;
ochange = IP_TRUE;
}
if (mchange)
{
int i;
/* Go through all IA's, and see if anyone requires any transactions */
for (i = 0; i < IPDHCPC6_IA_TYPE_MAX; i++)
{
Ipdhcpc6_ia_t *ia;
ia = IPCOM_LIST_FIRST(&ifp->ia_head[i]);
while (ia)
{
ia->table->reconfigure(ia);
ia = IPCOM_LIST_NEXT(&ia->next);
}
}
}
if (ochange)
{
/**/
if (ifp->runtime.other == IPDHCPC6_MODE_ENABLED)
{
#if 0 /* KONG verify this with "noroute" case */
/* if M flag is already enable, then do not send infor-request */
if (IPDHCPC6_MODE_ENABLED != ifp->runtime.managed)
#endif
ipdhcpc6_if_inforeq_start(ifp);
}
else
{
/* We're disabled; remove any references to this interface */
ipdhcpc6_info_update(ifp->context);
ipdhcpc6_if_inforeq_stop(ifp);
}
}
}
}
/*
*===========================================================================
* ipdhcpc6_if_schedule_transaction
*===========================================================================
* Description: Schedule a transaction
* Parameters: ifp - The interface pointer
* Returns:
*
*/
IP_GLOBAL void
ipdhcpc6_if_schedule_transaction(Ipdhcpc6_if_t *ifp)
{
ipcom_tmo2_cancel(&ifp->intr);
ipcom_tmo2_request(ifp->context->context->tmo_head,
&ifp->intr,
(Ipcom_tmo2_func)ipdhcpc6_if_run_transactions,
ifp,
0);
}
/*
*===========================================================================
* ipdhcpc6_if_address_remove
*===========================================================================
* Description: Remove an address from an interface
* Parameters: ifp - The interface
* binding - The binding.
* Returns:
*
*/
IP_GLOBAL void
ipdhcpc6_if_address_remove(Ipdhcpc6_if_t *ifp,
Ipdhcpc6_attr_binding_t *binding)
{
struct Ip_in6_ifreq ireq;
int ret = 0;
if (binding->status != IPDHCPC6_IA_ADDRESS_BOUND)
return;
ipcom_memset(&ireq, 0, sizeof(ireq));
ipcom_strncpy(ireq.ifr_name, ifp->ifname, sizeof(ireq.ifr_name));
ireq.ifr_ifru.ifru_addr.sin6_family = IP_AF_INET6;
IPCOM_SA_LEN_SET(&ireq.ifr_ifru.ifru_addr, sizeof(struct Ip_sockaddr_in6));
ipcom_memcpy(&ireq.ifr_ifru.ifru_addr.sin6_addr, &binding->prefix.addr, sizeof(binding->prefix.addr));
/* NOTE : IPNET can delete this address because the timeout */
ret = ipdhcpc6_util_ioctl(IP_SIOCDIFADDR_IN6, &ireq, ifp->vr);
if (ret < 0 && ipcom_errno != IP_ERRNO_EADDRNOTAVAIL)
{
/* LOG */
IPCOM_LOG4(ERR,
"%s: Failed to delete address %s from interface [%d, %s]",
ifp->context->context->name,
ipdhcpc6_util_ntoa(&ifp->context->context->ntoa, &binding->prefix.addr),
ifp->vr,
ifp->ifname);
}
else
{
IPCOM_LOG4(INFO,
"%s: delete address %s from interface [%d, %s]",
ifp->context->context->name,
ipdhcpc6_util_ntoa(&ifp->context->context->ntoa, &binding->prefix.addr),
ifp->vr,
ifp->ifname);
}
binding->status = IPDHCPC6_IA_ADDRESS_UNBOUND;
}
/*
*===========================================================================
* ipdhcpc6_init_addrs
*===========================================================================
* Description: Sets the address pointer to point to the correct entry
* in the 'rt' buffer.
* Parameters: rt - Route message.
* addrs - Will contain the route pointer.
* Returns:
*
*/
IP_STATIC void
ipdhcpc6_init_addrs(struct Ipnet_ifa_msghdr *ifa, struct Ip_sockaddr **addrs)
{
int i;
Ip_size_t offset;
offset = sizeof(struct Ipnet_ifa_msghdr);
for (i = 0; i < IPNET_RTAX_MAX; i++)
{
if (IP_BIT_ISSET(ifa->ifam_addrs, 1 << i))
{
addrs[i] = (struct Ip_sockaddr *) &((Ip_u8 *) ifa)[offset];
offset += IPCOM_SA_LEN_GET(addrs[i]) ? IP_ROUNDUP(IPCOM_SA_LEN_GET(addrs[i]), sizeof(Ip_u32)) : sizeof(Ip_u32);
}
else
addrs[i] = IP_NULL;
}
ip_assert(offset == ifa->ifam_msglen);
}
Ip_bool ipdhcpc6_if_has_addr (const Ipdhcpc6_if_t *ifp, const Ipdhcpc6_attr_prefix_t *prefix)
{
#if defined(IP_PORT_VXWORKS) && defined(IPLITE)
Ip_u32 ifindex = 0;
struct Ip_ifaddrs *ifaddrs = IP_NULL;
struct Ip_ifaddrs *ifaddr = IP_NULL;
struct Ip_sockaddr_in6 *s_in = IP_NULL;
ifindex = ipcom_if_nametoindex (ifp->ifname);
ipcom_getifaddrs(&ifaddrs);
for (ifaddr = ifaddrs; ifaddr != IP_NULL; ifaddr = ifaddr->ifa_next)
{
if (ifaddr->ifa_addr->sa_family == IP_AF_INET6 &&
ipcom_if_nametoindex(ifaddr->ifa_name) == ifindex)
{
s_in = (struct Ip_sockaddr_in6 *)(ifaddr->ifa_addr);
if (IP_IN6_ARE_ADDR_EQUAL(&prefix->addr, &s_in->sin6_addr))
{
return IP_TRUE;
}
}
}
return IP_FALSE;
#else
Ip_u32 ifindex;
int name[6];
int ret = IP_FALSE;
struct Ipnet_ifa_msghdr *ifa;
struct Ipnet_if_msghdr *ifm = IP_NULL;
Ip_size_t ifm_len;
Ip_size_t offset;
struct Ip_sockaddr *addrs[IPNET_RTAX_MAX];
#if IPCOM_VR_MAX > 1
int cur_vr = ipcom_proc_vr_get();
if (cur_vr != ifp->vr)
ipcom_proc_vr_set(ifp->vr);
#endif
ifindex = ipcom_if_nametoindex (ifp->ifname);
/*get the ifindex*/
name[0] = IP_CTL_NET;
name[1] = IP_AF_ROUTE;
name[2] = 0;
name[3] = IP_AF_INET6;
name[4] = IP_NET_RT_IFLIST;
name[5] = (int)ifindex;
/* Get length of data */
if (ipcom_sysctl(name, 6, IP_NULL, &ifm_len, IP_NULL, 0) < 0)
{
IPCOM_LOG1(ERR, "ipdhcpc6_if_has_addr: ipcom_sysctl() failed: %s",
ipcom_strerror(ipcom_errno));
goto cleanup;
}
/* Allocate space for data */
ifm = ipcom_malloc(ifm_len);
if (ifm == IP_NULL)
{
IPCOM_LOG0(ERR, "ipdhcpc6_if_has_addr: out of memory");
goto cleanup;
}
/* Get the actual data */
if (ipcom_sysctl(name, 6, ifm, &ifm_len, IP_NULL, 0) < 0)
{
IPCOM_LOG1(ERR, "ipdhcpc6_if_has_addr: ipcom_sysctl() failed: %s",
ipcom_strerror(ipcom_errno));
ret = -1;
goto cleanup;
}
for (offset = ifm->ifm_msglen; offset < ifm_len; offset += ifa->ifam_msglen)
{
struct Ip_sockaddr_in6 *addr;
ifa = (struct Ipnet_ifa_msghdr *) ((Ip_u8 *) ifm + offset);
ipdhcpc6_init_addrs(ifa, addrs);
if (ifa->ifam_type != IPNET_RTM_NEWADDR || addrs[IPNET_RTAX_IFA]->sa_family != IP_AF_INET6)
break;
addr = (struct Ip_sockaddr_in6 *) addrs[IPNET_RTAX_IFA];
if (addr != IP_NULL && IP_IN6_ARE_ADDR_EQUAL(&prefix->addr, &addr->sin6_addr))
{ /*if we found the address attached to the interface return true*/
ret = IP_TRUE;
break;
}
}
cleanup:
ipcom_free(ifm);
#if IPCOM_VR_MAX > 1
if (cur_vr != ifp->vr)
ipcom_proc_vr_set(cur_vr);
#endif
return(ret);
#endif
}
/*
*===========================================================================
* ipdhcpc6_if_address_add
*===========================================================================
* Description: Add an address to an interface
* Parameters: ifp - The interface
* binding - The binding.
* Returns:
*
*/
IP_GLOBAL Ip_bool
ipdhcpc6_if_address_add(Ipdhcpc6_ia_t *ia,
Ipdhcpc6_attr_binding_t *binding)
{
struct Ip_in6_aliasreq areq;
Ip_u8 len;
Ip_u8 bits;
Ipdhcpc6_if_t *ifp = ia->ifp;
if (binding->status == IPDHCPC6_IA_ADDRESS_BOUND)
return IP_FALSE;
/* Address didn't exist */
ipcom_memset(&areq, 0, sizeof(areq));
ipcom_strncpy(areq.ifra_name, ifp->ifname, sizeof(areq.ifra_name));
/* Create the prefix mask */
len = (Ip_u8) (binding->prefix.plen >> 3);
/* Set all bytes */
ipcom_memset(&areq.ifra_prefixmask.sin6_addr, 0xff, len);
/* Set any individual bits */
bits = (Ip_u8) (binding->prefix.plen & 7);
if (bits != 0)
{
/* Mask them in */
areq.ifra_prefixmask.sin6_addr.in6.addr8[len] = (Ip_u8) (0xff00 >> bits);
}
areq.ifra_prefixmask.sin6_family = IP_AF_INET6;
areq.ifra_prefixmask.sin6_len = sizeof(areq.ifra_prefixmask);
/* Set lifetimes */
areq.ifra_lifetime.ia6t_preferred = binding->preferred + binding->timestamp;
areq.ifra_lifetime.ia6t_expire = binding->valid + binding->timestamp;
/* Set address values */
areq.ifra_addr.sin6_family = IP_AF_INET6;
areq.ifra_addr.sin6_len = sizeof(areq.ifra_addr);
ipcom_memcpy(&areq.ifra_addr.sin6_addr, &binding->prefix.addr, sizeof(binding->prefix.addr));
/* Sanity */
areq.ifra_flags = IP_IN6_IFF_TENTATIVE;
if (ipdhcpc6_util_ioctl(IP_SIOCAIFADDR_IN6, &areq, ifp->vr) < 0)
{
/* LOG */
IPCOM_LOG4(ERR,
"%s: Failed to add address %s to interface [%d, %s]",
ifp->context->context->name,
ipdhcpc6_util_ntoa(&ifp->context->context->ntoa, &binding->prefix.addr),
ifp->vr,
ifp->ifname);
return IP_FALSE;
}
else
{
/*here mean add the address to the interface, if we check the address some times
and find it still exists, that means dad failed, address is avaiable!*/
/*true mean sends a decline message*/
if (ipdhcpc6_ia_na_dad_parse (ia, binding)==IP_TRUE)
return IP_FALSE;
binding->status = IPDHCPC6_IA_ADDRESS_BOUND;
IPCOM_LOG4(INFO,
"%s: Added address %s to interface [%d, %s]",
ifp->context->context->name,
ipdhcpc6_util_ntoa(&ifp->context->context->ntoa, &binding->prefix.addr),
ifp->vr,
ifp->ifname);
return IP_TRUE;
}
}
/*
*===========================================================================
* ipdhcpc6_if_address_update
*===========================================================================
* Description: Update an address to an interface
* Parameters: ifp - The interface
* binding - The binding.
* Returns:
*
*/
IP_GLOBAL Ip_bool
ipdhcpc6_if_address_update(Ipdhcpc6_if_t *ifp,
Ipdhcpc6_attr_binding_t *binding)
{
struct Ip_in6_aliasreq areq;
Ip_u8 len;
Ip_u8 bits;
if (binding->status != IPDHCPC6_IA_ADDRESS_BOUND)
return IP_FALSE;
/* Address didn't exist */
ipcom_memset(&areq, 0, sizeof(areq));
ipcom_strncpy(areq.ifra_name, ifp->ifname, sizeof(areq.ifra_name));
/* Create the prefix mask */
len = (Ip_u8) (binding->prefix.plen >> 3);
/* Set all bytes */
ipcom_memset(&areq.ifra_prefixmask.sin6_addr, 0xff, len);
/* Set any individual bits */
bits = (Ip_u8) (binding->prefix.plen & 7);
if (bits != 0)
{
/* Mask them in */
areq.ifra_prefixmask.sin6_addr.in6.addr8[len] = (Ip_u8) (0xff00 >> bits);
}
areq.ifra_prefixmask.sin6_family = IP_AF_INET6;
areq.ifra_prefixmask.sin6_len = sizeof(areq.ifra_prefixmask);
/* Set lifetimes */
areq.ifra_lifetime.ia6t_preferred = binding->preferred + binding->timestamp;
areq.ifra_lifetime.ia6t_expire = binding->valid + binding->timestamp;
/* Set address values */
areq.ifra_addr.sin6_family = IP_AF_INET6;
areq.ifra_addr.sin6_len = sizeof(areq.ifra_addr);
ipcom_memcpy(&areq.ifra_addr.sin6_addr, &binding->prefix.addr, sizeof(binding->prefix.addr));
/* Sanity */
areq.ifra_flags = IP_IN6_IFF_TENTATIVE;
if (ipdhcpc6_util_ioctl(IP_SIOCAIFADDR_IN6, &areq, ifp->vr) < 0)
{
/* LOG */
IPCOM_LOG3(ERR,
"%s: Failed to update address %s to interface %s",
ifp->context->context->name,
ipdhcpc6_util_ntoa(&ifp->context->context->ntoa, &binding->prefix.addr),
ifp->ifname);
return IP_FALSE;
}
else
{
IPCOM_LOG3(INFO,
"%s: Updated address %s to interface %s",
ifp->context->context->name,
ipdhcpc6_util_ntoa(&ifp->context->context->ntoa, &binding->prefix.addr),
ifp->ifname);
return IP_TRUE;
}
}
/*
*===========================================================================
* ipdhcpc6_if_prefix_set
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL void
ipdhcpc6_if_prefix_set(Ipdhcpc6_if_t *ifp,
Ipdhcpc6_attr_binding_t *binding)
{
if (ipdhcpc6_rtadv_prefix_set(ifp->context->context, ifp, binding) == IP_FALSE)
{
/* Go 64 */
binding->prefix.plen = 64;
}
}
/*
*===========================================================================
* ipdhcpc6_if_server_attr
*===========================================================================
* Description: Add a server attribute object to a buffer
* Parameters: buf - The buffer
* srv - The server attribute.
* Returns:
*
*/
IP_GLOBAL void
ipdhcpc6_if_server_attr(Ipdhcpc6_tagcomm_buffer_t *buf,
Ipdhcpc6_if_server_t *srv)
{
const struct Ip_in6_addr *unicast = ipdhcpc6_attr_server_unicast(srv->attr);
ipdhcpc6_tagcomm_enter_tag(buf,
IPDHCPC6_IA_OBJECT_SERVER,
IPDHCPC6_TAGCOMM_STATUS_OK);
ipdhcpc6_tagcomm_add_tag(buf,
IPDHCPC6_IA_IDENT_DUID,
IPDHCPC6_TAGCOMM_STATUS_OK,
srv->attr->id_vector,
srv->attr->id_size);
ipdhcpc6_tagcomm_add_tag(buf,
IPDHCPC6_IA_ATTR_ADDRESS,
IPDHCPC6_TAGCOMM_STATUS_OK,
&srv->attr->address,
sizeof(srv->attr->address));
if (srv->attr->info_refresh)
{
ipdhcpc6_tagcomm_add_tag(buf,
IPDHCPC6_IA_ATTR_SERVER_INFO_REFRESH,
IPDHCPC6_TAGCOMM_STATUS_OK,
&srv->attr->info_refresh,
sizeof(srv->attr->info_refresh));
}
if (unicast)
{
ipdhcpc6_tagcomm_add_tag(buf,
IPDHCPC6_IA_ATTR_SERVER_UNICAST,
IPDHCPC6_TAGCOMM_STATUS_OK,
(void *)unicast,
sizeof(*unicast));
}
if (srv->ifp->runtime.other == IPDHCPC6_MODE_ENABLED)
{
int i;
if (srv->ifp->conf.sntp == IPDHCPC6_MODE_ENABLED)
{
for (i = 0; i < (int)srv->attr->sntp.num; i++)
{
struct Ip_in6_addr *addr = srv->attr->sntp.array[i];
ipdhcpc6_tagcomm_add_tag(buf,
IPDHCPC6_IA_ATTR_SERVER_SNTP_SERVER,
IPDHCPC6_TAGCOMM_STATUS_OK,
addr,
sizeof(*addr));
}
}
if (srv->ifp->conf.dns == IPDHCPC6_MODE_ENABLED)
{
for (i = 0; i < (int)srv->attr->dns.num; i++)
{
struct Ip_in6_addr *addr = srv->attr->dns.array[i];
ipdhcpc6_tagcomm_add_tag(buf,
IPDHCPC6_IA_ATTR_SERVER_DNS_SERVER,
IPDHCPC6_TAGCOMM_STATUS_OK,
addr,
sizeof(*addr));
}
for (i = 0; i < (int)srv->attr->domain.num; i++)
{
char *domain = srv->attr->domain.array[i];
ipdhcpc6_tagcomm_add_tag(buf,
IPDHCPC6_IA_ATTR_SERVER_DOMAIN_LIST,
IPDHCPC6_TAGCOMM_STATUS_OK,
domain,
ipcom_strlen(domain) + 1);
}
}
if (srv->ifp->conf.sip == IPDHCPC6_MODE_ENABLED)
{
for (i = 0; i < (int)srv->attr->sip_d.num; i++)
{
char *domain = srv->attr->sip_d.array[i];
ipdhcpc6_tagcomm_add_tag(buf,
IPDHCPC6_IA_ATTR_SERVER_SIP_D,
IPDHCPC6_TAGCOMM_STATUS_OK,
domain,
ipcom_strlen(domain) + 1);
}
for (i = 0; i < (int)srv->attr->sip_a.num; i++)
{
struct Ip_in6_addr *addr = srv->attr->sip_a.array[i];
ipdhcpc6_tagcomm_add_tag(buf,
IPDHCPC6_IA_ATTR_SERVER_SIP_A,
IPDHCPC6_TAGCOMM_STATUS_OK,
addr,
sizeof(*addr));
}
}
if (srv->ifp->conf.fqdn.fqdn == IPDHCPC6_MODE_ENABLED
&& srv->attr->fqdn.num > 0)
{
ipdhcpc6_tagcomm_add_tag(buf,
IPDHCPC6_IA_ATTR_SERVER_FQDN,
IPDHCPC6_TAGCOMM_STATUS_OK,
srv->attr->fqdn.array[0],
ipcom_strlen(srv->attr->fqdn.array[0]) + 1);
}
}
ipdhcpc6_tagcomm_leave_tag(buf);
}
/*
*===========================================================================
* ipdhcpc6_if_link_local
*===========================================================================
* Description: Verify and return the link local address of the interface
* Parameters: ifp - The interface
* Returns: The link local if found and verified.
*
*/
IP_GLOBAL const struct Ip_in6_addr *
ipdhcpc6_if_link_local(Ipdhcpc6_if_t *ifp)
{
/**/
struct Ip_ifaddrs *ifaddrs;
struct Ip_in6_addr *llocal = IP_NULL;
Ip_u32 ifindex = ipdhcpc6_if_nametoindex(ifp->ifname, ifp->vr);
struct Ip_ifaddrs *ifaddr;
struct Ip_in6_aliasreq ifareq;
#if IPCOM_VR_MAX > 1
int vr = ipcom_proc_vr_get();
#endif
if (ifindex == 0)
return IP_NULL;
/* Already have it? */
if (ifp->have_link_local)
return &ifp->link_local;
#if IPCOM_VR_MAX > 1
if (vr != ifp->vr)
ipcom_proc_vr_set(ifp->vr);
#endif
/* Prepare the ioctl structure */
ipcom_strncpy(ifareq.ifra_name, ifp->ifname, sizeof(ifareq.ifra_name));
/* Get interface addresses */
ipcom_getifaddrs(&ifaddrs);
/* Verify that the address exists */
for (ifaddr = ifaddrs; ifaddr != IP_NULL; ifaddr = ifaddr->ifa_next)
{
if (ifaddr->ifa_addr->sa_family == IP_AF_INET6 &&
ipcom_if_nametoindex(ifaddr->ifa_name) == ifindex)
{
struct Ip_sockaddr_in6 *s_in = (struct Ip_sockaddr_in6 *) (ifaddr->ifa_addr);
ipcom_memcpy(&ifareq.ifra_addr, s_in, sizeof(ifareq.ifra_addr));
#ifndef IPLITE
/* Get address information */
if (ipdhcpc6_util_ioctl(IP_SIOCXGIFADDR_IN6, &ifareq, ifp->vr) < 0)
continue;
/* */
if (IP_BIT_ISSET(ifareq.ifra_flags, IP_IN6_IFF_ANYCAST|IP_IN6_IFF_TENTATIVE))
continue;
#endif
/* Is it link local? */
if (IP_IN6_IS_ADDR_LINK_LOCAL(&s_in->sin6_addr))
{
ipcom_memcpy(&ifp->link_local, &s_in->sin6_addr, sizeof(ifp->link_local));
ifp->have_link_local = IP_TRUE;
llocal = &ifp->link_local;
break;
}
}
}
/* Free the interface addresses */
ipcom_freeifaddrs(ifaddrs);
#if IPCOM_VR_MAX > 1
if (vr != ifp->vr)
ipcom_proc_vr_set(vr);
#endif
return llocal;
}
/*
*===========================================================================
* ipdhcpc6_if_server_restart
*===========================================================================
* Description: Restart any information refresh timers.
* Parameters: ifctx - The interface context.
* srv - The server
* Returns:
*
*/
IP_GLOBAL void
ipdhcpc6_if_server_restart(Ipdhcpc6_if_context_t *ifctx,
Ipdhcpc6_if_server_t *srv)
{
Ip_u32 remain;
ipcom_tmo2_cancel(&srv->refresh);
remain = ipdhcpc6_if_server_remain(srv);
if (remain != 0xffffffff)
{
ipcom_tmo2_request(ifctx->context->tmo_head,
&srv->refresh,
(Ipcom_tmo2_func) ipdhcpc6_if_server_timeout,
srv,
remain * 1000);
}
}
/*
*===========================================================================
* ipdhcpc6_if_inforeq_stop
*===========================================================================
* Description: Stop all outstanding information request transactions.
* Parameters:
* Returns:
*
*/
IP_GLOBAL void
ipdhcpc6_if_inforeq_stop(Ipdhcpc6_if_t *ifp)
{
/* Remove myself from any ongoing transactions */
ipdhcpc6_msg_transaction_dereference(&ifp->inforef);
ifp->inforeq_required = IP_FALSE;
}
/*
*===========================================================================
* ipdhcpc6_if_inforeq_start
*===========================================================================
* Description: Start the information request transaction if required.
* Parameters: ifp - The interface.
* Returns:
*
*/
IP_GLOBAL void
ipdhcpc6_if_inforeq_start(Ipdhcpc6_if_t *ifp)
{
if (ipdhcpc6_msg_transaction_reference_invalid(&ifp->inforef))
{
ifp->inforeq_required = IP_TRUE;
ipdhcpc6_if_schedule_transaction(ifp);
}
}
/*
****************************************************************************
* 11 PUBLIC FUNCTIONS
****************************************************************************
*/
/*
****************************************************************************
* END OF FILE
****************************************************************************
*/