1870 lines
59 KiB
C
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
|
|
****************************************************************************
|
|
*/
|