/* ****************************************************************************** * 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 ****************************************************************************** */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #include "ipdhcpc6_config.h" /* **************************************************************************** * 3 INCLUDE FILES **************************************************************************** */ #define IPCOM_USE_CLIB_PROTO #include #include #include #include #include #include #include #include #include #include #include #include #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 **************************************************************************** */