/* ****************************************************************************** * INTERPEAK SOURCE FILE * * Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipmip6mn_service_dsmipv6.c,v $ $Revision: 1.8 $ * $Source: /home/interpeak/CVSRoot/ipmip6mn/config/ipmip6mn_service_dsmipv6.c,v $ * $Author: jhorteli $ * $State: Exp $ $Locker: $ * * INTERPEAK_COPYRIGHT_STRING * Design and implementation by Joel Hortelius ****************************************************************************** */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #include "ipmip6mn_config.h" /* **************************************************************************** * 3 INCLUDE FILES **************************************************************************** */ #define IPCOM_USE_CLIB_PROTO #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ipmip6mn_h.h" #include "ipmip6mn_pktbuf.h" #include "ipmip6mn_bc.h" #include "ipmip6mn_mh.h" #include "ipmip6mn_mh_ha.h" #include "ipmip6mn_mib_update.h" #include "ipmip6mn_route.h" #include "ipmip6mn_attr_h.h" #if defined(IPMIP_USE_INET) /* **************************************************************************** * 4 DEFINES **************************************************************************** */ #define IPMIP6MN_SERVICE_DSMIPV6_NAME "dsmipv6" /* **************************************************************************** * 5 TYPES **************************************************************************** */ typedef struct Ipmip6mn_service_dsmipv6_config { Ip_bool dhcp_server; Ip_u32 offer_timeout; Ipcom_list options; } Ipmip6mn_service_dsmipv6_config_t; typedef struct Ipmip6mn_service_dsmipv6_lease_lookup { Ip_size_t sz; Ip_u8 *data; } Ipmip6mn_service_dsmipv6_lease_lookup_t; typedef struct Ipmip6mn_service_dsmipv6_gw { Ipcom_list next; Ipmip_dhcp_lease_t *lease; Ip_u32 mask; } Ipmip6mn_service_dsmipv6_gw_t; typedef struct Ipmip6mn_service_dsmipv6_node_dhcp { Ipcom_list next; Ipmip_dhcp_pool_t *pool; Ipmip_dhcp_node_t node; Ipmip_if_t *iff; Ipmip_dhcp_rtab_t *rtab; Ipcom_hash *leases; Ipmip6mn_node_t *mn; Ipcom_list gws; Ipmip6mn_service_dsmipv6_config_t *cfg; } Ipmip6mn_service_dsmipv6_node_dhcp_t; typedef struct Ipmip6mn_service_dsmipv6_lease { Ipmip_timer_t timer; Ipmip_dhcp_lease_t *lease; Ipmip6mn_service_dsmipv6_node_dhcp_t *db; Ip_u32 gateway; Ip_size_t len; char identity[1]; } Ipmip6mn_service_dsmipv6_lease_t; typedef struct Ipmip6mn_service_dsmipv6_node { Ipcom_list pools; } Ipmip6mn_service_dsmipv6_node_t; /* **************************************************************************** * 6 EXTERN PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 7 LOCAL PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 8 DATA **************************************************************************** */ /* **************************************************************************** * 9 STATIC FUNCTIONS **************************************************************************** */ IP_STATIC void ipmip6mn_service_dsmipv6_lease_free(Ipmip6mn_context_t *ctx, Ipmip_proc_t *proc, Ipmip_dhcp_lease_t *dlease) { Ipmip6mn_service_dsmipv6_lease_t *lease = dlease->opaque; if (lease != IP_NULL) { ipcom_hash_remove(lease->db->leases, lease); ipmip_timer_cancel(&ctx->ipmip6.ipmip, proc, &lease->timer); ipcom_free(lease); } } /* *=========================================================================== * ipmip6mn_service_dsmipv6_key_hash_id *=========================================================================== * Description: * Parameters: * Returns: */ IP_STATIC unsigned ipmip6mn_service_dsmipv6_key_hash_id(Ipmip6mn_service_dsmipv6_lease_lookup_t *id) { return ipcom_hash_update(id->data, (int)id->sz, 0); } /* *=========================================================================== * ipmip6mn_service_dsmipv6_obj_hash_id *=========================================================================== * Description: * Parameters: * Returns: */ IP_STATIC unsigned ipmip6mn_service_dsmipv6_obj_hash_id(Ipmip6mn_service_dsmipv6_lease_t *lease) { return ipcom_hash_update(lease->identity, (int)lease->len, 0); } /* *=========================================================================== * ipmip6pm_node_cmp_nai *=========================================================================== * Description: * Parameters: * Returns: */ IP_STATIC Ip_bool ipmip6mn_service_dsmipv6_cmp_id(Ipmip6mn_service_dsmipv6_lease_t *lease, Ipmip6mn_service_dsmipv6_lease_lookup_t *id) { /* Compare */ return ipmip_util_strnncmp(lease->identity, lease->len, (char *)id->data, id->sz); } IP_STATIC Ipmip6mn_service_dsmipv6_gw_t * ipmip6mn_service_dsmipv6_gateway_get(Ipmip6mn_service_dsmipv6_node_dhcp_t *node, Ip_u32 addr) { Ipmip6mn_service_dsmipv6_gw_t *gw; for (gw = IPCOM_LIST_FIRST(&node->gws); gw != IP_NULL; gw = IPCOM_LIST_NEXT(&gw->next)) { if ((gw->lease->prefix & gw->mask) == (addr & gw->mask)) return gw; } return IP_NULL; } IP_STATIC int ipmip6mn_service_dsmipv6_lease_timeout(int event, Ipmip6mn_context_t *ctx, Ipmip_proc_t *proc, Ipmip6mn_service_dsmipv6_lease_t *lease, void *unused) { IPMIP_UNUSED_PARAMETER(unused); if (event == IPMIP_TIMER_EVENT_RUN) ipmip_dhcp_lease_delete(&ctx->ipmip6.ipmip, proc, lease->lease); return IPMIP_TIMER_RET_DONE; } IP_STATIC Ipmip6mn_service_dsmipv6_lease_t * ipmip6mn_service_dsmipv6_lease_create(Ipmip6mn_context_t *ctx, Ipmip_proc_t *proc, Ipmip6mn_service_dsmipv6_node_dhcp_t *node, Ip_u8 *ident, Ip_size_t sz, Ip_u32 req_addr, int rule) { Ipmip6mn_service_dsmipv6_lease_t *lease = ipcom_calloc(1, sizeof(*lease) + sz); Ipmip6mn_service_dsmipv6_gw_t *gw; ipcom_memcpy(&lease->identity[0], ident, sz); lease->len = sz; lease->db = node; lease->lease = ipmip_dhcp_pool_lease_alloc(&ctx->ipmip6.ipmip, proc, node->pool, req_addr, 32, rule, lease); if (lease->lease == IP_NULL) { ipcom_free(lease); return IP_NULL; } if ((gw = ipmip6mn_service_dsmipv6_gateway_get(node, lease->lease->prefix)) == IP_NULL) { ipmip_dhcp_lease_delete(&ctx->ipmip6.ipmip, proc, lease->lease); return IP_NULL; } /* OK */ lease->gateway = gw->lease->prefix; ipcom_hash_add(node->leases, lease); ipmip_timer_request(&ctx->ipmip6.ipmip, proc, &lease->timer, node->node.lock, (Ipmip_timer_func_t)ipmip6mn_service_dsmipv6_lease_timeout, lease, IP_NULL, node->cfg->offer_timeout * 1000); return lease; } IP_STATIC int ipmip6mn_service_dsmipv6_dhcpv4_server(int event, Ipmip6mn_context_t *ctx, Ipmip_proc_t *proc, Ipmip_dhcp_node_t *dnode, Ipmip6mn_pktbuf_t *pbuf) { if (event == IPMIP_TIMER_EVENT_RUN) { Ipmip6mn_service_dsmipv6_node_dhcp_t *lnode = dnode->opaque; Ipmip_dhcp_hdr_t *pkt = (Ipmip_dhcp_hdr_t *)IPMIP_BUFFER_PTR(&pbuf->ipmip6.ipmip.packet); if (pkt->op == IPMIP_DHCP_OP_BOOTREQUEST) { Ip_u8 *opt; if ((opt = ipmip_dhcp_option_buffer_find(&pbuf->ipmip6.ipmip.packet, IPMIP_DHCP_OPTCODE_DHCP_MESSAGE_TYPE)) == IP_NULL) { IPMIP6_EVENT_IF(ERR, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "No MESSAGE TYPE in DHCP Request Received by %s", lnode->mn->name)); goto done_out; } else { Ipmip6mn_pktbuf_t *rpkt = (Ipmip6mn_pktbuf_t*)ipmip_pktbuf_alloc(&ctx->ipmip6.ipmip, proc, 512); Ipmip_buffer_t *buf = &rpkt->ipmip6.ipmip.packet; Ipmip6mn_service_dsmipv6_lease_lookup_t dlookup; Ipmip6mn_service_dsmipv6_lease_t *lease = IP_NULL; Ipmip_dhcp_option_t *opt_entry; Ip_u8 type; Ip_u8 *req_opt = ipmip_dhcp_option_buffer_find(&pbuf->ipmip6.ipmip.packet, IPMIP_DHCP_OPTCODE_DHCP_PARAMETER_REQUEST_LIST); Ip_u8 *ra_opt = ipmip_dhcp_option_buffer_find(&pbuf->ipmip6.ipmip.packet, IPMIP_DHCP_OPTCODE_RELAY_AGENT_INFO); Ip_u8 *cid = ipmip_dhcp_option_buffer_find(&pbuf->ipmip6.ipmip.packet, IPMIP_DHCP_OPTCODE_CLIENT_IDENTIFIER); Ip_u32 tmp32; Ip_u32 sid = 0; Ip_time_t lifetime = ipmip_util_time(); if (lifetime >= lnode->mn->home_agent.expires) lifetime = 10; else lifetime = lnode->mn->home_agent.expires - lifetime; /* Add the packet */ ipmip_buffer_append(buf, pkt, sizeof(*pkt)); dlookup.data = cid? &cid[IPMIP_DHCP_OPT_DATA] : &pkt->chaddr[0]; dlookup.sz = (Ip_size_t)(cid? cid[IPMIP_DHCP_OPT_LEN] : pkt->hlen); lease = ipcom_hash_get(lnode->leases, &dlookup); sid = ipmip_dhcp_option_buffer_find_ip(&pbuf->ipmip6.ipmip.packet, IPMIP_DHCP_OPTCODE_DHCP_SERVER_IDENTIFIER); switch(opt[IPMIP_DHCP_OPT_DATA]) { case IPMIP_DHCP_MSG_DISCOVER: IPMIP6_EVENT_IF(INFO, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "DHCP Discover Received by %s", lnode->mn->name)); type = IPMIP_DHCP_MSG_OFFER; if (lease == IP_NULL) { if ((lease = ipmip6mn_service_dsmipv6_lease_create(ctx, proc, lnode, dlookup.data, dlookup.sz, 0, IPMIP_DHCP_ALLOC_ANY)) == IP_NULL) goto done_out; } break; case IPMIP_DHCP_MSG_REQUEST: { Ip_u32 req_addr = 0; IPMIP6_EVENT_IF(INFO, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "DHCP Request Received by %s", lnode->mn->name)); req_addr = ipmip_dhcp_option_buffer_find_ip(&pbuf->ipmip6.ipmip.packet, IPMIP_DHCP_OPTCODE_DHCP_REQUESTED_ADDRESS); if (req_addr == 0) req_addr = IP_GET_32ON8(&pkt->ciaddr); if (sid != 0) { if (lease != IP_NULL) { if (lease->gateway != sid) goto done_out; } else { Ipmip6mn_service_dsmipv6_gw_t *gw; for (gw = IPCOM_LIST_FIRST(&lnode->gws); gw != IP_NULL; gw = IPCOM_LIST_NEXT(&gw->next)) if (gw->lease->prefix == sid) break; if (gw == IP_NULL) goto done_out; } } if (req_addr != 0 && (lease == IP_NULL || req_addr == lease->lease->prefix)) { type = IPMIP_DHCP_MSG_ACK; if (lease == IP_NULL) { if ((lease = ipmip6mn_service_dsmipv6_lease_create(ctx, proc, lnode, dlookup.data, dlookup.sz, req_addr, IPMIP_DHCP_ALLOC_EXACT)) == IP_NULL) { type = IPMIP_DHCP_MSG_NAK; break; } else sid = lease->gateway; } /**/ ipmip_timer_cancel(&ctx->ipmip6.ipmip, proc, &lease->timer); ipmip_timer_request(&ctx->ipmip6.ipmip, proc, &lease->timer, lnode->node.lock, (Ipmip_timer_func_t)ipmip6mn_service_dsmipv6_lease_timeout, lease, IP_NULL, (Ip_u32)lifetime * 1000); } else { type = IPMIP_DHCP_MSG_NAK; } } break; case IPMIP_DHCP_MSG_DECLINE: /* Do what? */ IPMIP6_EVENT_IF(INFO, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "DHCP Decline Received by %s", lnode->mn->name)); if (lease != IP_NULL) { ipmip_timer_cancel(&ctx->ipmip6.ipmip, proc, &lease->timer); ipcom_hash_remove(lnode->leases, lease); } goto done_out; case IPMIP_DHCP_MSG_RELEASE: /* Do what? */ IPMIP6_EVENT_IF(INFO, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "DHCP Release Received by %s", lnode->mn->name)); if (lease != IP_NULL) ipmip_dhcp_lease_delete(&ctx->ipmip6.ipmip, proc, lease->lease); goto done_out; case IPMIP_DHCP_MSG_INFORM: /* Do what? */ IPMIP6_EVENT_IF(INFO, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "DHCP Inform Received by %s", lnode->mn->name)); if (lease != IP_NULL && IP_GET_32ON8(&pkt->ciaddr) == lease->lease->prefix) type = IPMIP_DHCP_MSG_INFORM_ACK; else type = IPMIP_DHCP_MSG_NAK; break; default: IPMIP6_EVENT_IF(INFO, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "DHCP unknown Received by %s", lnode->mn->name)); goto done_out; } if (sid == 0) { if (lease != IP_NULL) sid = lease->gateway; else { Ipmip6mn_service_dsmipv6_gw_t *gw = IPCOM_LIST_FIRST(&lnode->gws); sid = gw->lease->prefix; } } /* Add TYPE */ ipmip_dhcp_option_buffer_append_u8(buf, IPMIP_DHCP_OPTCODE_DHCP_MESSAGE_TYPE, type); ipmip_dhcp_option_buffer_append_ip(buf, IPMIP_DHCP_OPTCODE_DHCP_SERVER_IDENTIFIER, sid); if (type != IPMIP_DHCP_MSG_NAK) { /* ACK or INFORM_ACK */ if (type != IPMIP_DHCP_MSG_INFORM_ACK) { ipmip_dhcp_option_buffer_append_u32(buf, IPMIP_DHCP_OPTCODE_DHCP_LEASE_TIME, (Ip_u32)lifetime); } /* Add the basic options */ /* Subnet */ tmp32 = 0; ipmip_util_create_mask((Ip_u8 *)&tmp32, lease->lease->netmask_bits); ipmip_dhcp_option_buffer_append_ip(buf, IPMIP_DHCP_OPTCODE_SUBNET_MASK, tmp32); /* Gateway */ ipmip_dhcp_option_buffer_append_ip(buf, IPMIP_DHCP_OPTCODE_ROUTERS, sid); if (req_opt) { for (tmp32 = 0; tmp32 < req_opt[IPMIP_DHCP_OPT_LEN]; tmp32++) { opt_entry = ipmip_dhcp_option_entry_find(&lnode->cfg->options, req_opt[IPMIP_DHCP_OPT_DATA + tmp32]); if (opt_entry != IP_NULL) ipmip_dhcp_buffer_append_option_entry(buf, opt_entry); } } /* Add rest */ for (opt_entry = IPCOM_LIST_FIRST(&lnode->cfg->options); opt_entry != IP_NULL; opt_entry = IPCOM_LIST_NEXT(&opt_entry->next)) ipmip_dhcp_buffer_append_option_entry(buf, opt_entry); } else { /* NAK */ } if (ra_opt) ipmip_dhcp_option_buffer_append(buf, IPMIP_DHCP_OPTCODE_RELAY_AGENT_INFO, ra_opt[IPMIP_DHCP_OPT_LEN], &ra_opt[IPMIP_DHCP_OPT_DATA]); ipmip_dhcp_option_buffer_close(buf); pkt = (Ipmip_dhcp_hdr_t *)IPMIP_BUFFER_PTR(buf); pkt->op = IPMIP_DHCP_OP_BOOTREPLY; pkt->hops = 0; if (type != IPMIP_DHCP_MSG_NAK && type != IPMIP_DHCP_MSG_INFORM_ACK) IP_SET_32ON8(&pkt->yiaddr, lease->lease->prefix); ipmip_dhcp_server_reply(&ctx->ipmip6.ipmip, proc, &rpkt->ipmip6.ipmip, sid, lnode->iff, type == IPMIP_DHCP_MSG_NAK); } } else { IPMIP6_EVENT_IF(ERR, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "DHCP Reply Received for %s", lnode->mn->name)); } } done_out: /* Free the DHCP packet */ ipmip_pktbuf_release(&ctx->ipmip6.ipmip, proc, &pbuf->ipmip6.ipmip); return IPMIP_TIMER_RET_DONE; } IP_STATIC void ipmip6mn_service_dsmipv6_config_dhcp_options(struct Ipmip_proc *proc, char *name, char *subkey, const char *value, Ipmip6mn_service_dsmipv6_config_t *priv_cfg) { Ipmip_dhcp_option_t *opt = ipmip_dhcp_option_parse_name(proc, subkey, value, IP_NULL); IPMIP_UNUSED_PARAMETER(proc); IPMIP_UNUSED_PARAMETER(name); if (opt != IP_NULL) ipcom_list_insert_first(&priv_cfg->options, &opt->next); } IP_STATIC void ipmip6mn_service_dsmipv6_config(struct Ipmip6mn_context *ctx, struct Ipmip_proc *proc, int action, struct Ipmip6mn_node *node, struct Ipmip6mn_node_config *cfg, Ipmip6mn_service_dsmipv6_config_t *priv_cfg, Ipmip_cli_message_t *request) { IPMIP_UNUSED_PARAMETER(ctx); IPMIP_UNUSED_PARAMETER(proc); IPMIP_UNUSED_PARAMETER(cfg); if (action == IPMIP_CALLBACK_CONFIG_READ) { ipcom_list_init(&priv_cfg->options); priv_cfg->dhcp_server = ipmip_sysvar_bool(IP_FALSE, "ipmip6mn.%s.inet.mobile_router.dhcp.server", node->name); priv_cfg->offer_timeout = ipmip_sysvar_u32(10, "ipmip6mn.%s.inet.mobile_router.dhcp.server.offer.timeout", node->name); if (priv_cfg->dhcp_server) ipmip_dhcp_context_create(&ctx->ipmip6.ipmip, proc); ipmip_sysvar_foreach(proc, (Ipmip_sysvar_foreach_t)ipmip6mn_service_dsmipv6_config_dhcp_options, priv_cfg, "ipmip6mn.%s.inet.mobile_router.dhcp.server.option.*", node->name); } else if (action == IPMIP_CALLBACK_CONFIG_FREE) { Ipmip_dhcp_option_t *opt; /**/ while ((opt = IPCOM_LIST_FIRST(&priv_cfg->options)) != IP_NULL) { ipcom_list_remove(&opt->next); ipcom_free(opt); } } else if (action == IPMIP_CALLBACK_CONFIG_DUMP) { Ipmip_dhcp_option_t *opt; ipmip_cli_config_printf(&request->message, "ipmip6mn.%s.inet.mobile_router.dhcp.server=%s", node->name, priv_cfg->dhcp_server? "true" : "false"); ipmip_cli_config_printf(&request->message, "ipmip6mn.%s.inet.mobile_router.dhcp.server.offer.timeout=%d", node->name, priv_cfg->offer_timeout); /**/ for (opt = IPCOM_LIST_FIRST(&priv_cfg->options); opt != IP_NULL; opt = IPCOM_LIST_NEXT(&opt->next)) { const Ipmip_dhcp_option_def_t *dopt = ipmip_dhcp_option_def_code_get(opt->option[IPMIP_DHCP_OPT_CODE]); if (dopt != IP_NULL) { ipmip_cli_config_printf(&request->message, "ipmip6mn.%s.inet.mobile_router.dhcp.server.option.%s=%s", node->name, dopt->name, ipmip_dhcp_option_print(proc, opt->option, opt->type)); } else { ipmip_cli_config_printf(&request->message, "ipmip6mn.%s.inet.mobile_router.dhcp.server.option.%s.%u=%s", node->name, ipmip_dhcp_type_name[opt->type], opt->option[IPMIP_DHCP_OPT_CODE], ipmip_dhcp_option_print(proc, opt->option, opt->type)); } } } } IP_STATIC int ipmip6mn_service_dsmipv6_provide(struct Ipmip6mn_context *ctx, struct Ipmip_proc *proc, int action, struct Ipmip6mn_node *node, struct Ipmip6mn_node_config *cfg, Ipmip6mn_service_dsmipv6_config_t *dscfg, Ipmip6mn_service_dsmipv6_node_t *handle, struct Ipmip_timer *service) { Ipmip6mn_dsmipv6_nemo_prefix_t *dsnemo; Ipmip6mn_service_dsmipv6_node_dhcp_t *dhcp; Ipmip6mn_service_dsmipv6_gw_t *gw; IPMIP_UNUSED_PARAMETER(dscfg); IPMIP_UNUSED_PARAMETER(cfg); IPMIP_UNUSED_PARAMETER(service); if (action == IPMIP_CALLBACK_ENABLE) { ipcom_list_init(&handle->pools); if (dscfg->dhcp_server) { for (dsnemo = IPCOM_LIST_FIRST(&cfg->dsmipv6.prefixes); dsnemo != IP_NULL; dsnemo = IPCOM_LIST_NEXT(&dsnemo->next)) { if (dsnemo->nemo && dsnemo->nemo->nemo_if.ifindex != 0 && dsnemo->request_prefix && dsnemo->updated == IP_TRUE && dsnemo->status == IPMIP6_MH_BU_DSMIPV6_HOA_ACK_SUCCESS) { /* Do some kind of processing based on the data */ Ip_u32 subnet = dsnemo->runtime_prefix; /* Do we have a pool for this already? */ for (dhcp = IPCOM_LIST_FIRST(&handle->pools); dhcp != IP_NULL; dhcp = IPCOM_LIST_NEXT(&dhcp->next)) if (dhcp->node.ifindex == dsnemo->nemo->nemo_if.ifindex) break; /**/ if (dhcp == IP_NULL) { dhcp = ipcom_calloc(1, sizeof(*dhcp)); dhcp->cfg = dscfg; dhcp->rtab = ipmip_dhcp_rtab_create(&ctx->ipmip6.ipmip, proc, (Ipmip_dhcp_lease_free_t)ipmip6mn_service_dsmipv6_lease_free); dhcp->pool = ipmip_dhcp_pool_create(&ctx->ipmip6.ipmip, proc, dsnemo->nemo->nemo_if.ifname, dhcp->rtab); dhcp->mn = node; dhcp->iff = &dsnemo->nemo->nemo_if; dhcp->leases = ipcom_hash_new((Ipcom_hash_obj_func) ipmip6mn_service_dsmipv6_obj_hash_id, (Ipcom_hash_key_func) ipmip6mn_service_dsmipv6_key_hash_id, (Ipcom_hash_cmp_func) ipmip6mn_service_dsmipv6_cmp_id); /**/ dhcp->node.ifindex = dsnemo->nemo->nemo_if.ifindex; dhcp->node.lock = node->persistent.lock; dhcp->node.opaque = dhcp; dhcp->node.process_func = (Ipmip_timer_func_t)ipmip6mn_service_dsmipv6_dhcpv4_server; ipcom_list_init(&dhcp->gws); /* Register this pool */ ipmip_dhcp_register(&ctx->ipmip6.ipmip, proc, &dhcp->node); ipcom_list_insert_last(&handle->pools, &dhcp->next); } ipmip_dhcp_pool_add_slice(dhcp->pool, subnet, 0, dsnemo->runtime_prefix_length, 32); /* Need to add a gateway? */ if (ipmip6mn_service_dsmipv6_gateway_get(dhcp, subnet) == IP_NULL) { /* Create a static lease for the gateway for this subnet */ gw = ipcom_calloc(1, sizeof(*gw)); gw->lease = ipmip_dhcp_pool_lease_alloc(&ctx->ipmip6.ipmip, proc, dhcp->pool, ipcom_htonl(ip_ntohl(subnet) + 1), 32, IPMIP_DHCP_ALLOC_EXACT, IP_NULL); ipmip_util_create_mask((Ip_u8 *)&gw->mask, dsnemo->runtime_prefix_length); ipcom_list_insert_last(&dhcp->gws, &gw->next); if (ipmip_netlink_inX_addr(&ctx->ipmip6.ipmip, proc, IP_AF_INET, IP_RTM_NEWADDR, dhcp->node.ifindex, &gw->lease->prefix, gw->lease->netmask_bits, 0, 0) < 0) { IPMIP6_EVENT_IF(ERR, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "%s unable to add address %s/%d to interface %s", node->name, ipmip_ntop_inet(proc, gw->lease->prefix), gw->lease->netmask_bits, dsnemo->nemo->nemo_if.ifname)); } } } } } } else if (action == IPMIP_CALLBACK_DISABLE) { while ((dhcp = IPCOM_LIST_FIRST(&handle->pools)) != IP_NULL) { ipcom_list_remove(&dhcp->next); while ((gw = IPCOM_LIST_FIRST(&dhcp->gws)) != IP_NULL) { ipcom_list_remove(&gw->next); if (ipmip_netlink_inX_addr(&ctx->ipmip6.ipmip, proc, IP_AF_INET, IP_RTM_DELADDR, dhcp->node.ifindex, &gw->lease->prefix, gw->lease->netmask_bits, 0, 0) < 0) { IPMIP6_EVENT_IF(ERR, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "%s unable to add address %s/%d to interface %s", node->name, ipmip_ntop_inet(proc, gw->lease->prefix), gw->lease->netmask_bits, dhcp->iff->ifname)); } ipcom_free(gw); } ipmip_dhcp_pool_destroy(&ctx->ipmip6.ipmip, proc, dhcp->pool); ipmip_dhcp_rtab_destroy(dhcp->rtab); ipcom_hash_delete(dhcp->leases); ipcom_free(dhcp); } } return IPMIP_CALLBACK_RET_SUCCESS; } /* **************************************************************************** * 10 GLOBAL FUNCTIONS **************************************************************************** */ IP_GLOBAL void ipmip6mn_service_dsmipv6_install(struct Ipmip6mn_context *ctx); IP_GLOBAL void ipmip6mn_service_dsmipv6_install(struct Ipmip6mn_context *ctx) { static Ipmip6mn_extension_t srv; srv.name = IPMIP6MN_SERVICE_DSMIPV6_NAME; srv.node_data_size = sizeof(Ipmip6mn_service_dsmipv6_node_t); srv.node_config_size = sizeof(Ipmip6mn_service_dsmipv6_config_t); srv.config = (Ipmip6mn_extension_config_t)ipmip6mn_service_dsmipv6_config; srv.provide = (Ipmip6mn_extension_provide_t)ipmip6mn_service_dsmipv6_provide; /* This is a PMIP only feature */ ipmip6mn_context_register_extension(ctx, &srv); } /* **************************************************************************** * 11 PUBLIC FUNCTIONS **************************************************************************** */ #else /* IPMIP_USE_INET */ IP_GLOBAL void ipmip6mn_service_dsmipv6_install(struct Ipmip6mn_context *ctx); IP_GLOBAL void ipmip6mn_service_dsmipv6_install(struct Ipmip6mn_context *ctx) { IPMIP_UNUSED_PARAMETER(ctx); } #endif /* **************************************************************************** * END OF FILE **************************************************************************** */