/* ****************************************************************************** * INTERPEAK SOURCE FILE * * Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipmip6pm_service_dsmipv6.c,v $ $Revision: 1.10 $ * $Source: /home/interpeak/CVSRoot/ipmip6pm/config/ipmip6pm_service_dsmipv6.c,v $ * $Author: jhorteli $ * $State: Exp $ $Locker: $ * * INTERPEAK_COPYRIGHT_STRING * Design and implementation by Joel Hortelius ****************************************************************************** */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #include "ipmip6pm_config.h" #ifdef IPMIP_USE_INET /* **************************************************************************** * 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 #include #include #include "ipmip6pm_h.h" #include "ipmip6pm_attr_h.h" #include "ipmip6pm_if.h" #include "ipmip6pm_node.h" #include "ipmip6pm_pktbuf.h" /* **************************************************************************** * 4 DEFINES **************************************************************************** */ #define IPMIP6PM_SERVICE_DSMIPV6_NAME "DSMIPV6" #define IPMIP6PM_SERVICE_INSTALLED_DHCP (1 << 0) #define IPMIP6PM_SERVICE_INSTALLED_ARP (1 << 1) /* **************************************************************************** * 5 TYPES **************************************************************************** */ typedef struct Ipmip6pm_service_dsmipv6_config_global { struct { Ip_bool enabled; } server_config; struct { Ip_bool enabled; Ip_u32 forward; Ip_bool override; Ip_bool link_selection; } relay_config; } Ipmip6pm_service_dsmipv6_config_global_t; typedef struct Ipmip6pm_service_dsmipv6_config { struct { Ip_bool enabled; } server_config; struct { Ip_bool enabled; Ip_u32 forward; Ip_bool override; Ip_bool link_selection; } relay_config; } Ipmip6pm_service_dsmipv6_config_t; typedef struct Ipmip6pm_service_dsmipv6_relay { Ip_u32 forward; } Ipmip6pm_service_dsmipv6_relay_t; typedef struct Ipmip6pm_service_dsmipv6_node { /* MUST be first */ Ipmip_dhcp_node_t dhcp; Ipmip_arp_node_t arp; Ip_u32 installed; Ipmip6pm_service_dsmipv6_relay_t relay_data; Ip_bool relay; Ip_u32 gateway; Ipmip6pm_service_dsmipv6_config_t *cfg; } Ipmip6pm_service_dsmipv6_node_t; /* **************************************************************************** * 6 EXTERN PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 7 LOCAL PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 8 DATA **************************************************************************** */ /* **************************************************************************** * 9 STATIC FUNCTIONS **************************************************************************** */ IP_STATIC int ipmip6pm_service_dsmipv6_arp(int event, Ipmip6pm_context_t *ctx, Ipmip_proc_t *proc, Ipmip_arp_node_t *arp, Ipmip6pm_pktbuf_t *pbuf) { if (event == IPMIP_TIMER_EVENT_RUN) { Ipmip_arp_hdr_t *pkt = (Ipmip_arp_hdr_t *)IPMIP_BUFFER_PTR(&pbuf->ipmip6.ipmip.packet); Ipmip6pm_node_t *node = arp->opaque; if (pkt->op == IPMIP_ARP_OP_REQUEST) { /* Don't reply to the node's own */ if (IP_GET_32ON8(&pkt->ip_dst[0]) != node->mo_dsmipv6_home_prefix.prefix) { IPMIP6_EVENT_IF(DEBUG2, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "ARP Request Received by %s", ipmip6pm_node_describe(proc, node))); ipmip_inet_arp_reply(&ctx->ipmip6.ipmip, proc, pkt, &node->ifp_private.ipmip6.ifp->iff); } } } /* Free the DHCP packet */ ipmip_pktbuf_release(&ctx->ipmip6.ipmip, proc, &pbuf->ipmip6.ipmip); return IPMIP_TIMER_RET_DONE; } IP_STATIC int ipmip6pm_service_dsmipv6_dhcpv4_relay(int event, Ipmip6pm_context_t *ctx, Ipmip_proc_t *proc, Ipmip6pm_service_dsmipv6_node_t *dnode, Ipmip6pm_pktbuf_t *pbuf) { if (event == IPMIP_TIMER_EVENT_RUN) { Ipmip6pm_node_t *node = dnode->dhcp.opaque; int ra_opt; Ipmip_dhcp_hdr_t *pkt = (Ipmip_dhcp_hdr_t *)IPMIP_BUFFER_PTR(&pbuf->ipmip6.ipmip.packet); Ip_u8 *opt; opt = ipmip_dhcp_option_buffer_find(&pbuf->ipmip6.ipmip.packet, IPMIP_DHCP_OPTCODE_DHCP_MESSAGE_TYPE); if (pkt->op == IPMIP_DHCP_OP_BOOTREQUEST) { if (opt == IP_NULL) { IPMIP6_EVENT_IF(ERR, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "DHCP Request Received by %s contained no MESSAGE_TYPE", ipmip6pm_node_describe(proc, node))); goto done_out; } if (opt[IPMIP_DHCP_OPT_DATA] == IPMIP_DHCP_MSG_REQUEST) { Ip_u32 ciaddr = IP_GET_32ON8(&pkt->ciaddr); if (ciaddr == 0) ciaddr = ipmip_dhcp_option_buffer_find_ip(&pbuf->ipmip6.ipmip.packet, IPMIP_DHCP_OPTCODE_DHCP_REQUESTED_ADDRESS); if (ciaddr != node->mo_dsmipv6_home_prefix.prefix) { IPMIP6_EVENT_IF(ERR, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "DHCP REQUEST Received for %s CIADDR mismatch %s != %s", ipmip6pm_node_describe(proc, node), ipmip_ntop_inet(proc, ciaddr), ipmip_ntop_inet(proc, node->mo_dsmipv6_home_prefix.prefix))); goto done_out; } } IPMIP6_EVENT_IF(DEBUG, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "DHCP Request Received by %s relaying to %s", ipmip6pm_node_describe(proc, node), ipmip_ntop_inet(proc, dnode->relay_data.forward))); /* */ IP_SET_32ON8(&pkt->giaddr, node->ifp_public->ifinet); pkt->hops++; /**/ ipmip_dhcp_option_buffer_open(&pbuf->ipmip6.ipmip.packet, IPMIP_DHCP_OPTCODE_END); /**/ ra_opt = ipmip_dhcp_option_buffer_init(&pbuf->ipmip6.ipmip.packet, IPMIP_DHCP_OPTCODE_RELAY_AGENT_INFO); if (dnode->cfg->relay_config.link_selection) ipmip_dhcp_option_buffer_append(&pbuf->ipmip6.ipmip.packet, IPMIP_DHCP_SUBOPTCODE_RA_LINK_SELECTION, sizeof(Ip_u32), &node->mo_dsmipv6_home_prefix.prefix); if (dnode->cfg->relay_config.override) ipmip_dhcp_option_buffer_append(&pbuf->ipmip6.ipmip.packet, IPMIP_DHCP_SUBOPTCODE_RA_SERVER_OVERRIDE, sizeof(Ip_u32), &dnode->gateway); ipmip_dhcp_option_buffer_append(&pbuf->ipmip6.ipmip.packet, IPMIP_DHCP_SUBOPTCODE_RA_REMOTE_ID, sizeof(Ip_u32), &node->mo_dsmipv6_home_prefix.prefix); ipmip_dhcp_option_buffer_append(&pbuf->ipmip6.ipmip.packet, IPMIP_DHCP_SUBOPTCODE_RA_CIRCUIT_ID, sizeof(Ip_u32), &dnode->dhcp.ifindex); ipmip_dhcp_option_buffer_end(&pbuf->ipmip6.ipmip.packet, ra_opt); ipmip_dhcp_option_buffer_close(&pbuf->ipmip6.ipmip.packet); /* */ ipmip_dhcp_relay_to_server(&ctx->ipmip6.ipmip, proc, &pbuf->ipmip6.ipmip, node->ifp_public->ifinet, dnode->relay_data.forward); } else { Ipmip6pm_if_priv_t *ifp = (Ipmip6pm_if_priv_t *)node->ifp_private.ipmip6.ifp; if (opt == IP_NULL) { IPMIP6_EVENT_IF(ERR, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "DHCP Reply Received for %s contained no MESSAGE_TYPE", ipmip6pm_node_describe(proc, node))); goto done_out; } /**/ if (opt[IPMIP_DHCP_OPT_DATA] == IPMIP_DHCP_MSG_OFFER) { if (IP_GET_32ON8(&pkt->yiaddr) != node->mo_dsmipv6_home_prefix.prefix) { IPMIP6_EVENT_IF(ERR, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "DHCP OFFER Received for %s YIADDR mismatch %s != %s", ipmip6pm_node_describe(proc, node), ipmip_ntop_inet(proc, IP_GET_32ON8(&pkt->yiaddr)), ipmip_ntop_inet(proc,node->mo_dsmipv6_home_prefix.prefix))); goto done_out; } } IPMIP6_EVENT_IF(DEBUG, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "DHCP Reply Received for %s", ipmip6pm_node_describe(proc, node))); ipmip_dhcp_write_to_client(&ctx->ipmip6.ipmip, proc, &pbuf->ipmip6.ipmip, dnode->gateway, &ifp->ipmip6.iff, IP_FALSE); } } /* Free the DHCP packet */ done_out: ipmip_pktbuf_release(&ctx->ipmip6.ipmip, proc, &pbuf->ipmip6.ipmip); return IPMIP_TIMER_RET_DONE; } IP_STATIC int ipmip6pm_service_dsmipv6_dhcpv4_server(int event, Ipmip6pm_context_t *ctx, Ipmip_proc_t *proc, Ipmip6pm_service_dsmipv6_node_t *dnode, Ipmip6pm_pktbuf_t *pbuf) { if (event == IPMIP_TIMER_EVENT_RUN) { Ipmip6pm_node_t *node = dnode->dhcp.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 (IP_GET_32ON8(&pkt->giaddr) == 0 && ipmip_dhcp_option_buffer_find(&pbuf->ipmip6.ipmip.packet, IPMIP_DHCP_OPTCODE_RELAY_AGENT_INFO) == IP_NULL) { 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", ipmip6pm_node_describe(proc, node))); goto done_out; } else { Ipmip6pm_pktbuf_t *rpkt = (Ipmip6pm_pktbuf_t*)ipmip_pktbuf_alloc(&ctx->ipmip6.ipmip, proc, 512); Ipmip_buffer_t *buf = &rpkt->ipmip6.ipmip.packet; Ip_u8 type; #if 0 Ip_u8 *req_opt = ipmip_dhcp_option_buffer_find(&pbuf->ipmip6.ipmip.packet, IPMIP_DHCP_OPTCODE_DHCP_PARAMETER_REQUEST_LIST); #endif Ip_u32 tmp32; /* Add the packet */ ipmip_buffer_append(buf, pkt, sizeof(*pkt)); switch(opt[IPMIP_DHCP_OPT_DATA]) { case IPMIP_DHCP_MSG_DISCOVER: IPMIP6_EVENT_IF(DEBUG, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "DHCP Discover Received by %s", ipmip6pm_node_describe(proc, node))); type = IPMIP_DHCP_MSG_OFFER; break; case IPMIP_DHCP_MSG_REQUEST: { Ip_u32 sid = 0; Ip_u32 req_addr = 0; IPMIP6_EVENT_IF(DEBUG, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "DHCP Request Received by %s", ipmip6pm_node_describe(proc, node))); sid = ipmip_dhcp_option_buffer_find_ip(&pbuf->ipmip6.ipmip.packet, IPMIP_DHCP_OPTCODE_DHCP_SERVER_IDENTIFIER); 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 && sid != dnode->gateway) goto done_out; if (req_addr != 0 && req_addr == node->mo_dsmipv6_home_prefix.prefix) type = IPMIP_DHCP_MSG_ACK; else type = IPMIP_DHCP_MSG_NAK; } break; case IPMIP_DHCP_MSG_DECLINE: /* Do what? */ IPMIP6_EVENT_IF(DEBUG, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "DHCP Decline Received by %s", ipmip6pm_node_describe(proc, node))); goto done_out; case IPMIP_DHCP_MSG_RELEASE: /* Do what? */ IPMIP6_EVENT_IF(DEBUG, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "DHCP Release Received by %s", ipmip6pm_node_describe(proc, node))); goto done_out; case IPMIP_DHCP_MSG_INFORM: /* Do what? */ IPMIP6_EVENT_IF(DEBUG, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "DHCP Inform Received by %s", ipmip6pm_node_describe(proc, node))); if (IP_GET_32ON8(&pkt->ciaddr) == node->mo_dsmipv6_home_prefix.prefix) type = IPMIP_DHCP_MSG_INFORM_ACK; else type = IPMIP_DHCP_MSG_NAK; break; default: IPMIP6_EVENT_IF(WARNING, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "DHCP unknown Received by %s", ipmip6pm_node_describe(proc, node))); goto done_out; } /* 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, dnode->gateway); if (type != IPMIP_DHCP_MSG_NAK) { /* ACK or INFORM_ACK */ if (type != IPMIP_DHCP_MSG_INFORM_ACK) { #ifndef IPTESTENGINE ipmip_dhcp_option_buffer_append_u32(buf, IPMIP_DHCP_OPTCODE_DHCP_LEASE_TIME, node->remaining); #else ipmip_dhcp_option_buffer_append_u32(buf, IPMIP_DHCP_OPTCODE_DHCP_LEASE_TIME, 5); #endif } /* Add the basic options */ /* Subnet */ tmp32 = 0; ipmip_util_create_mask((Ip_u8 *)&tmp32, node->mo_dsmipv6_home_prefix.len); 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, dnode->gateway); } else { /* NAK */ } 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, node->mo_dsmipv6_home_prefix.prefix); /* Send */ ipmip_dhcp_write_to_client(&ctx->ipmip6.ipmip, proc, &rpkt->ipmip6.ipmip, dnode->gateway, &node->ifp_private.ipmip6.ifp->iff, type == IPMIP_DHCP_MSG_NAK); } } else { IPMIP6_EVENT_IF(ERR, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "Relayed DHCP Request Received by %s", ipmip6pm_node_describe(proc, node))); } } else { IPMIP6_EVENT_IF(ERR, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "DHCP Reply Received for %s", ipmip6pm_node_describe(proc, node))); } } done_out: /* Free the DHCP packet */ ipmip_pktbuf_release(&ctx->ipmip6.ipmip, proc, &pbuf->ipmip6.ipmip); return IPMIP_TIMER_RET_DONE; } IP_STATIC Ip_bool ipmip6pm_service_dsmipv6_req_accept(struct Ipmip6pm_context *ctx, struct Ipmip_proc *proc, Ipmip6pm_service_dsmipv6_config_global_t *gcfg, Ipmip6pm_service_dsmipv6_config_t *cfg, Ipmip6pm_service_dsmipv6_node_t *handle, struct Ipmip6pm_node *node, struct Ipmip6pm_pktbuf *pbuf, struct Ipmip_timer *service) { IPMIP_UNUSED_PARAMETER(ctx); IPMIP_UNUSED_PARAMETER(proc); IPMIP_UNUSED_PARAMETER(cfg); IPMIP_UNUSED_PARAMETER(gcfg); IPMIP_UNUSED_PARAMETER(node); IPMIP_UNUSED_PARAMETER(service); if (pbuf->ipmip6.mo.pdsmipv6_default_router != IP_NULL) handle->gateway = IP_GET_32ON8(&pbuf->ipmip6.mo.pdsmipv6_default_router->gw); return IP_FALSE; } IP_STATIC void ipmip6pm_service_dsmipv6_config_global(struct Ipmip6pm_context *ctx, struct Ipmip_proc *proc, int action, Ipmip6pm_service_dsmipv6_config_global_t *gcfg, Ipmip_cli_message_t *request) { IPMIP_UNUSED_PARAMETER(ctx); IPMIP_UNUSED_PARAMETER(proc); if (action == IPMIP_CALLBACK_CONFIG_READ) { gcfg->relay_config.enabled = ipmip_sysvar_bool(IP_TRUE, "ipmip6pm.inet.dhcp.relay.enabled"); gcfg->relay_config.link_selection = ipmip_sysvar_bool(IP_FALSE, "ipmip6pm.inet.dhcp.relay.link_selection"); gcfg->relay_config.override = ipmip_sysvar_bool(IP_TRUE, "ipmip6pm.inet.dhcp.relay.server_override"); ipmip_sysvar_inet(0, &gcfg->relay_config.forward, IP_NULL, "ipmip6pm.inet.dhcp.relay.server"); gcfg->server_config.enabled = ipmip_sysvar_bool(IP_TRUE, "ipmip6pm.inet.dhcp.server.enabled"); } else if (action == IPMIP_CALLBACK_CONFIG_FREE) { /* Do nothing */ } else if (action == IPMIP_CALLBACK_CONFIG_DUMP) { ipmip_cli_config_printf(&request->message, "ipmip6pm.inet.dhcp.server.enabled=%s", gcfg->server_config.enabled? "enabled" : "disabled"); ipmip_cli_config_printf(&request->message, "ipmip6pm.inet.dhcp.relay.enabled=%s", gcfg->relay_config.enabled? "enabled" : "disabled"); ipmip_cli_config_printf(&request->message, "ipmip6pm.inet.dhcp.relay.link_selection=%s", gcfg->relay_config.link_selection? "true" : "false"); ipmip_cli_config_printf(&request->message, "ipmip6pm.inet.dhcp.relay.server_override=%s", gcfg->relay_config.override? "true" : "false"); if (gcfg->relay_config.forward) { ipmip_cli_config_printf(&request->message, "ipmip6pm.inet.dhcp.relay.server=%s", ipmip_ntop_inet(proc, gcfg->relay_config.forward)); } } } IP_STATIC void ipmip6pm_service_dsmipv6_config(struct Ipmip6pm_context *ctx, struct Ipmip_proc *proc, int action, struct Ipmip6pm_if *ifp, Ipmip6pm_service_dsmipv6_config_global_t *gcfg, Ipmip6pm_service_dsmipv6_config_t *cfg, Ipmip_cli_message_t *request) { IPMIP_UNUSED_PARAMETER(ctx); IPMIP_UNUSED_PARAMETER(proc); if (action == IPMIP_CALLBACK_CONFIG_READ) { cfg->relay_config.enabled = ipmip_sysvar_bool(gcfg->relay_config.enabled, "ipmip6pm.interface.%s.inet.dhcp.relay.enabled", ifp->ipmip6.iff.ifname); ipmip_sysvar_inet(gcfg->relay_config.forward, &cfg->relay_config.forward, IP_NULL, "ipmip6pm.interface.%s.inet.dhcp.relay.server", ifp->ipmip6.iff.ifname); cfg->relay_config.link_selection = ipmip_sysvar_bool(gcfg->relay_config.link_selection, "ipmip6pm.interface.%s.inet.dhcp.relay.link_selection", ifp->ipmip6.iff.ifname); cfg->relay_config.override = ipmip_sysvar_bool(gcfg->relay_config.override, "ipmip6pm.interface.%s.inet.dhcp.relay.server_override", ifp->ipmip6.iff.ifname); cfg->server_config.enabled = ipmip_sysvar_mode(gcfg->server_config.enabled, "ipmip6pm.interface.%s.inet.dhcp.server.enabled", ifp->ipmip6.iff.ifname); if (cfg->relay_config.enabled || cfg->server_config.enabled) { /* We need the DHCP context */ ipmip_dhcp_context_create(&ctx->ipmip6.ipmip, proc); } } else if (action == IPMIP_CALLBACK_CONFIG_FREE) { /* Do nothing */ } else if (action == IPMIP_CALLBACK_CONFIG_DUMP) { ipmip_cli_config_printf(&request->message, "ipmip6pm.interface.%s.inet.dhcp.server.enabled=%s", ifp->ipmip6.iff.ifname, cfg->server_config.enabled? "enabled" : "disabled"); ipmip_cli_config_printf(&request->message, "ipmip6pm.interface.%s.inet.dhcp.relay.enabled=%s", ifp->ipmip6.iff.ifname, cfg->relay_config.enabled? "enabled" : "disabled"); ipmip_cli_config_printf(&request->message, "ipmip6pm.interface.%s.inet.dhcp.relay.link_selection=%s", ifp->ipmip6.iff.ifname, cfg->relay_config.link_selection? "true" : "false"); ipmip_cli_config_printf(&request->message, "ipmip6pm.interface.%s.inet.dhcp.relay.server_override=%s", ifp->ipmip6.iff.ifname, cfg->relay_config.override? "true" : "false"); if (cfg->relay_config.forward) { ipmip_cli_config_printf(&request->message, "ipmip6pm.interface.%s.inet.dhcp.relay.server=%s", ifp->ipmip6.iff.ifname, ipmip_ntop_inet(proc, cfg->relay_config.forward)); } } } IP_STATIC int ipmip6pm_service_dsmipv6_provide(struct Ipmip6pm_context *ctx, struct Ipmip_proc *proc, int action, Ipmip6pm_service_dsmipv6_config_global_t *gcfg, Ipmip6pm_service_dsmipv6_config_t *cfg, Ipmip6pm_service_dsmipv6_node_t *handle, struct Ipmip6pm_node *node, struct Ipmip_timer *service) { IPMIP_UNUSED_PARAMETER(service); IPMIP_UNUSED_PARAMETER(cfg); IPMIP_UNUSED_PARAMETER(gcfg); if (action == IPMIP_CALLBACK_ENABLE) { /* Assign the gateway */ if (node->mo_dsmipv6_home_prefix.prefix != 0) { if (handle->gateway && !handle->relay) { if (ipmip_netlink_inX_addr(&ctx->ipmip6.ipmip, proc, IP_AF_INET, IP_RTM_NEWADDR, node->ifp_private.ipmip6.ifp->iff.ifindex, &handle->gateway, 32, 0, 0) != 0) { /**/ IPMIP6_EVENT_IF(ERR, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "Proxy Mobile node %s interface %s unable to add DSMIPv6 Gateway address %s", ipmip6pm_node_describe(proc, node), node->ifp_private.ipmip6.ifp->iff.ifname, ipmip_ntop_inet(proc, handle->gateway))); } } /* Setup the RELAY structure */ handle->dhcp.ifindex = node->ifp_private.ipmip6.ifp->iff.ifindex; handle->dhcp.lock = node->lock; handle->dhcp.opaque = node; handle->cfg = cfg; if (handle->relay) { if (node->ifp_public && node->ifp_public->ifinet) { /* * The relay agent won't work properly unless there is * an IPv4 address configured on the interface. * We can use the CoA for this purpose. */ if (ipmip_netlink_inX_addr(&ctx->ipmip6.ipmip, proc, IP_AF_INET, IP_RTM_NEWADDR, node->ifp_private.ipmip6.ifp->iff.ifindex, &node->ifp_public->ifinet, 32, 0, 0) != 0) { /**/ IPMIP6_EVENT_IF(ERR, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "Proxy Mobile node %s interface %s unable to add DSMIPv6 CoA address %s", ipmip6pm_node_describe(proc, node), node->ifp_private.ipmip6.ifp->iff.ifname, ipmip_ntop_inet(proc, node->ifp_public->ifinet))); } } handle->dhcp.remote_id = node->mo_dsmipv6_home_prefix.prefix; handle->dhcp.process_func = (Ipmip_timer_func_t)ipmip6pm_service_dsmipv6_dhcpv4_relay; ipmip_dhcp_register(&ctx->ipmip6.ipmip, proc, &handle->dhcp); } else { handle->dhcp.process_func = (Ipmip_timer_func_t)ipmip6pm_service_dsmipv6_dhcpv4_server; ipmip_dhcp_register(&ctx->ipmip6.ipmip, proc, &handle->dhcp); } handle->installed |= IPMIP6PM_SERVICE_INSTALLED_DHCP; if (node->ifp_private.ipmip6.ifp->iff.lladdr != IP_NULL && node->ifp_private.ipmip6.ifp->iff.lladdr->type == IPMIP_LLADDR_TYPE_MAC) { handle->arp.ifindex = node->ifp_private.ipmip6.ifp->iff.ifindex; handle->arp.lock = node->lock; handle->arp.opaque = node; handle->arp.process_func = (Ipmip_timer_func_t)ipmip6pm_service_dsmipv6_arp; ipmip_inet_arp_context_in_create(&ctx->ipmip6.ipmip, proc); ipmip_inet_arp_context_out_create(&ctx->ipmip6.ipmip, proc); ipmip_inet_arp_register(&ctx->ipmip6.ipmip, proc, &handle->arp); handle->installed |= IPMIP6PM_SERVICE_INSTALLED_ARP; } } } else if (action == IPMIP_CALLBACK_DISABLE || action == IPMIP_CALLBACK_UPDATE) { if (handle->relay && node->ifp_public && node->ifp_public->ifinet) { ipmip_netlink_inX_addr(&ctx->ipmip6.ipmip, proc, IP_AF_INET, IP_RTM_DELADDR, node->ifp_private.ipmip6.ifp->iff.ifindex, &node->ifp_public->ifinet, 32, 0, 0); } else if (handle->gateway) { ipmip_netlink_inX_addr(&ctx->ipmip6.ipmip, proc, IP_AF_INET, IP_RTM_DELADDR, node->ifp_private.ipmip6.ifp->iff.ifindex, &handle->gateway, 32, 0, 0); } if ((handle->installed & IPMIP6PM_SERVICE_INSTALLED_DHCP) != 0) { ipmip_dhcp_unregister(&ctx->ipmip6.ipmip, proc, &handle->dhcp); /**/ handle->installed &= ~IPMIP6PM_SERVICE_INSTALLED_DHCP; } if ((handle->installed & IPMIP6PM_SERVICE_INSTALLED_ARP) != 0) { ipmip_inet_arp_unregister(&ctx->ipmip6.ipmip, proc, &handle->arp); /**/ handle->installed &= ~IPMIP6PM_SERVICE_INSTALLED_ARP; } if (action == IPMIP_CALLBACK_UPDATE) return IPMIP_CALLBACK_RET_FAILED; } /* Don't delay */ return IPMIP_CALLBACK_RET_SUCCESS; } IP_STATIC Ip_bool ipmip6pm_service_dsmipv6_setup(struct Ipmip6pm_context *ctx, struct Ipmip_proc *proc, int action, Ipmip6pm_service_dsmipv6_config_global_t *gcfg, Ipmip6pm_service_dsmipv6_config_t *cfg, Ipmip6pm_service_dsmipv6_node_t *handle, struct Ipmip6pm_node *node, const char *value, Ipmip_cli_message_t *request) { IPMIP_UNUSED_PARAMETER(ctx); IPMIP_UNUSED_PARAMETER(proc); IPMIP_UNUSED_PARAMETER(gcfg); if (action == IPMIP_CALLBACK_CONFIG_READ) { int slen = value? ipcom_strlen(value) : 0; if (ctx->ipmip6.ipmip.dhcp == IP_NULL) return IP_FALSE; if (slen == 0 || value[0] != 'S') { if (cfg->relay_config.enabled == IP_FALSE) return IP_FALSE; /* RELAY */ if (slen > 2 && value[1] == '=') { ipmip_util_inet(&value[2], &handle->relay_data.forward, IP_NULL); } else { if (cfg->relay_config.forward) handle->relay_data.forward = cfg->relay_config.forward; else handle->relay_data.forward = node->homeagent_inet; } handle->relay = IP_TRUE; return IP_TRUE; } else { /* SERVER */ return cfg->server_config.enabled; } } else if (action == IPMIP_CALLBACK_CONFIG_FREE) { /* No dyncamically allocated values */ } else if (action == IPMIP_CALLBACK_CONFIG_DUMP) { if (handle->relay) { Ip_size_t rta = ipmip_attr_begin(&request->message, IPMIP6PM_CLI_ATTR_BC_P_SERVICE); ipmip_attr_put_str(&request->message, IPMIP6PM_CLI_ATTR_BC_P_SRV_MODULE, IPMIP6PM_SERVICE_DSMIPV6_NAME); ipcom_snprintf(proc->ntop.ntop_pbuf, sizeof(proc->ntop.ntop_pbuf), "R=%s", ipmip_ntop_inet(proc, handle->relay_data.forward)); ipmip_attr_put_str(&request->message, IPMIP6PM_CLI_ATTR_BC_P_SRV_VALUE, proc->ntop.ntop_pbuf); ipmip_attr_end(&request->message, rta); } else { Ip_size_t rta = ipmip_attr_begin(&request->message, IPMIP6PM_CLI_ATTR_BC_P_SERVICE); ipmip_attr_put_str(&request->message, IPMIP6PM_CLI_ATTR_BC_P_SRV_MODULE, IPMIP6PM_SERVICE_DSMIPV6_NAME); ipmip_attr_put_str(&request->message, IPMIP6PM_CLI_ATTR_BC_P_SRV_VALUE, "S"); ipmip_attr_end(&request->message, rta); } } return IP_FALSE; } /* **************************************************************************** * 10 GLOBAL FUNCTIONS **************************************************************************** */ IP_GLOBAL void ipmip6pm_service_dsmipv6_install(struct Ipmip6pm_context *ctx); IP_GLOBAL void ipmip6pm_service_dsmipv6_install(struct Ipmip6pm_context *ctx) { static Ipmip6pm_extension_t srv; srv.name = IPMIP6PM_SERVICE_DSMIPV6_NAME; srv.syntax = ""; srv.node_data_size = sizeof(Ipmip6pm_service_dsmipv6_node_t); srv.ifp_data_size = sizeof(Ipmip6pm_service_dsmipv6_config_t); srv.global_data_size = sizeof(Ipmip6pm_service_dsmipv6_config_global_t); srv.config_global = (Ipmip6pm_extension_config_global_t)ipmip6pm_service_dsmipv6_config_global; srv.config_ifp = (Ipmip6pm_extension_config_ifp_t)ipmip6pm_service_dsmipv6_config; srv.provide = (Ipmip6pm_extension_provide_t)ipmip6pm_service_dsmipv6_provide; srv.setup = (Ipmip6pm_extension_setup_t)ipmip6pm_service_dsmipv6_setup; srv.pkt_rep_accept = (Ipmip6pm_extension_pkt_rep_accept_t)ipmip6pm_service_dsmipv6_req_accept; ipmip6pm_context_register_extension(ctx, &srv, IPMIP6PM_FUNCTION_SERVICE); } /* **************************************************************************** * 11 PUBLIC FUNCTIONS **************************************************************************** */ #else IP_GLOBAL void ipmip6pm_service_dsmipv6_install(struct Ipmip6pm_context *ctx); IP_GLOBAL void ipmip6pm_service_dsmipv6_install(struct Ipmip6pm_context *ctx) { IPMIP_UNUSED_PARAMETER(ctx); } #endif /* **************************************************************************** * END OF FILE **************************************************************************** */