/* ****************************************************************************** * INTERPEAK SOURCE FILE * * Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipmipfa_pmipv4_dhcp.c,v $ $Revision: 1.8.16.2 $ * $Source: /home/interpeak/CVSRoot/ipmipfa/config/ipmipfa_pmipv4_dhcp.c,v $ * $Author: jsheng $ * $State: Exp $ $Locker: $ * * INTERPEAK_COPYRIGHT_STRING * Design and implementation by Joel Hortelius ****************************************************************************** */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #include "ipmipfa_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 #include "ipmipfa.h" #include "ipmipfa_h.h" #include "ipmipfa_attr_h.h" #include "ipmipfa_if.h" #include "ipmipfa_node.h" #include "ipmipfa_reg.h" #include "ipmipfa_pktbuf.h" /* **************************************************************************** * 4 DEFINES **************************************************************************** */ #define IPMIPFA_REGEXT_PMIPV4_DHCP "PMIPV4-DHCP" /* **************************************************************************** * 5 TYPES **************************************************************************** */ typedef struct Ipmipfa_pmipv4_dhcp_config_ifp { Ipmip_dhcp_node_t dhcp; struct Ipmipfa_iff *iff; char *domain; Ip_u16 port; Ip_u32 dhcp_relay_server; Ip_u32 dhcp_relay_server_override; Ip_u32 dhcp_proxy_address; Ip_u32 dhcp_home_agent; Ipmip_lladdr_t *fixed_link_layer; struct Ip_sockaddr_in pmipv4_in; Ipmip4_pkt_udp_register_t udpr; struct Ip_sockaddr_in sin4; /**/ Ipmip_arp_node_t arp; /* MN-HA secret */ Ip_u32 mn_ha_spi; struct Ip_iovec mn_ha_secretv; } Ipmipfa_pmipv4_dhcp_config_ifp_t; typedef struct Ipmipfa_pmipv4_dhcp_node_data { Ip_u32 dhcp_server; Ip_u32 dhcp_server_override; Ip_u32 home_agent; Ip_u32 mn_ha_spi; struct Ip_iovec mn_ha_spi_secret; Ipmipfa_pktbuf_t *dhcp_request; struct Ip_sockaddr_in *pmip_client; } Ipmipfa_pmipv4_dhcp_node_data_t; /* **************************************************************************** * 6 EXTERN PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 7 LOCAL PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 8 DATA **************************************************************************** */ static Ipmipfa_extension_t ipmipfa_pmipv4_dhcp; /* **************************************************************************** * 9 STATIC FUNCTIONS **************************************************************************** */ IP_STATIC void ipmipfa_pmipv4_dhcp_revoke_inform(struct Ipmipfa_data *ctx, struct Ipmip_proc *proc, void *global_config, Ipmipfa_pmipv4_dhcp_config_ifp_t *conf, Ipmipfa_pmipv4_dhcp_node_data_t *ndata, struct Ipmipfa_node *node) { /**/ Ipmip_buffer_t trigger; Ip_size_t rhdr; Ip_u8 type; IPMIP_UNUSED_PARAMETER(global_config); /* Populate trigger */ ipmip_buffer_init(&trigger); rhdr = ipmip_attr_hdr_req_create(&trigger, 0, node->mib.faVisitorHomeAddress.s_addr, IPMIP4_CLI_PMIPV4_PREVRQ); /**/ type = ipmip4_lla_pmipv4_access_type_from_lladdr_types(node->reginfo.faVisitorMAC->type, node->reginfo.faVisitorMAC->subtype); if (type != 0) ipmip_attr_put_u32(&trigger, IPMIP4_CLI_PMIPV4_ATTR_ACCESS_TYPE, type); if (IPMIP_LLADDR_LEN_LLA(node->reginfo.faVisitorMAC)) { ipmip_attr_put(&trigger, IPMIP4_CLI_PMIPV4_ATTR_INTERFACE_ID, IPMIP_LLADDR_LEN_LLA(node->reginfo.faVisitorMAC), IPMIP_LLADDR_DATA(node->reginfo.faVisitorMAC)); type = ipmip4_lla_pmipv4_device_id_type_from_lladdr_types(node->reginfo.faVisitorMAC->type, node->reginfo.faVisitorMAC->subtype); if (type != 0) { ipmip_attr_put(&trigger, IPMIP4_CLI_PMIPV4_ATTR_DEVICE_ID, IPMIP_LLADDR_LEN_LLA(node->reginfo.faVisitorMAC), IPMIP_LLADDR_DATA(node->reginfo.faVisitorMAC)); ipmip_attr_put_u32(&trigger, IPMIP4_CLI_PMIPV4_ATTR_DEVICE_ID_TYPE, type); } } /* */ ipmip_attr_put_inet(&trigger, IPMIP4_CLI_PMIPV4_ATTR_NFA_COA, node->ifp->iff.ifaddr); ipmip_attr_put_inet(&trigger, IPMIP4_CLI_PMIPV4_ATTR_HOA, node->mib.faVisitorHomeAddress.s_addr); ipmip_attr_put_inet(&trigger, IPMIP4_CLI_PMIPV4_ATTR_HA, node->mib.faVisitorHomeAgentAddress.s_addr); ipmip_attr_put(&trigger, IPMIP4_CLI_PMIPV4_ATTR_MN_NAI, IPMIP4_MSGEXT_SHDR_EXT_SIZE(node->nai), IPMIP4_MSGEXT_SHDR_EXT_DATA(node->nai)); ipmip_attr_hdr_finalize(&trigger, rhdr); /**/ { if (ipcom_sendto(conf->udpr.fd, IPMIP_BUFFER_DATA(&trigger), IPMIP_BUFFER_SIZE(&trigger), 0, (struct Ip_sockaddr *)ndata->pmip_client, sizeof(*ndata->pmip_client)) < 0) { IPMIP4_EVENT_IF(ERR, proc, ipmip_log_event_add(&ctx->ipmip4.ipmip, proc, "PMIPv4 UNABLE TO SEND REVOCATION TRIGGER")); } } ipmip_buffer_release(&trigger); } IP_STATIC void ipmipfa_pmipv4_dhcp_udp_transport(Ipmipfa_data_t *ctx, Ipmip_proc_t *proc, Ipmipfa_pktbuf_t *pbuf) { Ipmipfa_pmipv4_dhcp_config_ifp_t *conf = pbuf->rrp_transport_opaque; if (conf != IP_NULL) { Ipmip_buffer_t prrp; Ip_size_t rhdr; ipmip_buffer_init(&prrp); rhdr = ipmip_attr_hdr_req_create(&prrp, 0, 0, IPMIP4_CLI_PMIPV4_PRRQ); ipmip_attr_put(&prrp, IPMIP4_CLI_PMIPV4_ATTR_MESSAGE, IPMIP_BUFFER_SIZE(&pbuf->ipmip4.ipmip.packet), IPMIP_BUFFER_DATA(&pbuf->ipmip4.ipmip.packet)); ipmip_attr_hdr_finalize(&prrp, rhdr); if (ipcom_sendto(conf->udpr.fd, IPMIP_BUFFER_DATA(&prrp), IPMIP_BUFFER_SIZE(&prrp), 0, (struct Ip_sockaddr *)pbuf->ipmip4.ipmip.srcinfo.src, sizeof(pbuf->ipmip4.ipmip.srcinfo.src->sin)) < 0) { IPMIP4_EVENT_IF(ERR, proc, ipmip_log_event_add(&ctx->ipmip4.ipmip, proc, "UNABLE TO SEND PMIPv4 PRRP")); } ipmip_buffer_release(&prrp); } else { IPMIP4_EVENT_IF(ERR, proc, ipmip_log_event_add(&ctx->ipmip4.ipmip, proc, "UNABLE TO FORWARD PMIPv4 PRRP - NO CONTEXT")); } } IP_STATIC int ipmipfa_pmipv4_dhcp_node_arp(int event, Ipmipfa_data_t *ctx, Ipmip_proc_t *proc, Ipmipfa_pktbuf_t *pbuf, Ipmipfa_node_t *node) { if (event == IPMIP_TIMER_EVENT_RUN) { Ipmip_arp_hdr_t *pkt = (Ipmip_arp_hdr_t *)IPMIP_BUFFER_PTR(&pbuf->ipmip4.ipmip.packet); if (node != IP_NULL) { if (node->handler == &ipmipfa_pmipv4_dhcp) { /* Don't reply to the node's own */ if (IP_GET_32ON8(&pkt->ip_dst[0]) != node->mib.faVisitorHomeAddress.s_addr) { IPMIP4_EVENT_IF(DEBUG2, proc, ipmip_log_event_add(&ctx->ipmip4.ipmip, proc, "ARP Request Received by %s", ipmipfa_node_describe(proc, node))); ipmip_inet_arp_reply(&ctx->ipmip4.ipmip, proc, pkt, &pbuf->iff.pub->ipmip); } } } else { /* ipmip_inet_arp_reply(&ctx->ipmip4.ipmip, proc, pkt, &pbuf->iff.pub->ipmip); */ } } ipmip_pktbuf_release(&ctx->ipmip4.ipmip, proc, &pbuf->ipmip4.ipmip); return IPMIP_TIMER_RET_DONE; } IP_STATIC int ipmipfa_pmipv4_dhcp_arp(int event, Ipmipfa_data_t *ctx, Ipmip_proc_t *proc, Ipmip_arp_node_t *arp, Ipmipfa_pktbuf_t *pbuf) { if (event == IPMIP_TIMER_EVENT_RUN) { Ipmip_arp_hdr_t *pkt = (Ipmip_arp_hdr_t *)IPMIP_BUFFER_PTR(&pbuf->ipmip4.ipmip.packet); Ipmipfa_pmipv4_dhcp_config_ifp_t *cfg = arp->opaque; if (pkt->op == IPMIP_ARP_OP_REQUEST) { pbuf->iff.priv = cfg->iff; ipmipfa_node_findbykey(ctx, proc, cfg->iff, IP_GET_32ON8(&pkt->ip_src[0]), 0, IP_NULL, ipmip_lladdr_sanitize(cfg->iff->iff.ipmip.lladdr, pbuf->ipmip4.ipmip.srcinfo.lladdr), &pbuf->ipmip4.ipmip.timeout, (Ipmip_timer_func_t)ipmipfa_pmipv4_dhcp_node_arp, pbuf); return IPMIP_TIMER_RET_DONE; } } /* Free the DHCP packet */ ipmip_pktbuf_release(&ctx->ipmip4.ipmip, proc, &pbuf->ipmip4.ipmip); return IPMIP_TIMER_RET_DONE; } IP_STATIC Ip_bool ipmipfa_pmipv4_dhcp_nai(Ipmipfa_data_t *ctx, Ipmip_proc_t *proc, Ipmipfa_pmipv4_dhcp_config_ifp_t *dnode, Ipmipfa_pktbuf_t *pbuf, struct Ip_iovec *naiv) { Ipmip_dhcp_hdr_t *pkt = (Ipmip_dhcp_hdr_t *)IPMIP_BUFFER_PTR(&pbuf->ipmip4.ipmip.packet); struct Ip_iovec vec; /* NEED TO CREATE NAI -- only on requests */ if (pkt->op == IPMIP_DHCP_OP_BOOTREQUEST) { const char *nai; if (ipmip_dhcp_retrieve_client_id(&pbuf->ipmip4.ipmip.packet, &vec) && ((Ip_u8 *)vec.iov_base)[0] == 0) nai = ipmip_ntop_strn(proc, &((char *)vec.iov_base)[1], vec.iov_len - 1); else { ipcom_snprintf(proc->ntop.ntop_pbuf, sizeof(proc->ntop.ntop_pbuf), "%s@%s", ipmip_ntop_hex(proc, vec.iov_base, vec.iov_len), dnode->domain); nai = proc->ntop.ntop_pbuf; } /**/ naiv->iov_len = ipcom_strlen(nai); naiv->iov_base = (void *)nai; } else { Ip_u8 *ra_opt = ipmip_dhcp_option_buffer_find(&pbuf->ipmip4.ipmip.packet, IPMIP_DHCP_OPTCODE_RELAY_AGENT_INFO); Ip_u8 *rid = IP_NULL; /**/ if (ra_opt == IP_NULL) { IPMIP4_EVENT_IF(ERR, proc, ipmip_log_event_add(&ctx->ipmip4.ipmip, proc, "DHCP Request Reply Received contained no relay agent information")); return IP_FALSE; } /**/ rid = ipmip_dhcp_option_find(&ra_opt[IPMIP_DHCP_OPT_DATA], ra_opt[IPMIP_DHCP_OPT_LEN], IPMIP_DHCP_SUBOPTCODE_RA_REMOTE_ID); if (rid == IP_NULL) { IPMIP4_EVENT_IF(ERR, proc, ipmip_log_event_add(&ctx->ipmip4.ipmip, proc, "DHCP Request Reply Received contained no relay agent remote id information")); return IP_FALSE; } naiv->iov_len = rid[IPMIP_DHCP_OPT_LEN]; naiv->iov_base = &rid[IPMIP_DHCP_OPT_DATA]; } return IP_TRUE; } IP_STATIC void ipmipfa_pmipv4_dhcp_relay_forward_server(Ipmipfa_data_t *ctx, Ipmip_proc_t *proc, Ipmipfa_pktbuf_t *pbuf, Ipmipfa_node_t *node, Ipmipfa_pmipv4_dhcp_node_data_t *ndata) { Ipmip_dhcp_hdr_t *pkt = (Ipmip_dhcp_hdr_t *)IPMIP_BUFFER_PTR(&pbuf->ipmip4.ipmip.packet); int ra_opt; /* Do lookup on YIADDR/HA; If there's a node? */ /* */ IP_SET_32ON8(&pkt->giaddr, pbuf->iff.pub->ifaddr); pkt->hops++; /**/ ipmip_dhcp_option_buffer_open(&pbuf->ipmip4.ipmip.packet, IPMIP_DHCP_OPTCODE_END); ra_opt = ipmip_dhcp_option_buffer_init(&pbuf->ipmip4.ipmip.packet, IPMIP_DHCP_OPTCODE_RELAY_AGENT_INFO); ipmip_dhcp_option_buffer_append(&pbuf->ipmip4.ipmip.packet, IPMIP_DHCP_SUBOPTCODE_RA_CIRCUIT_ID, sizeof(Ip_u32), &pbuf->iff.pub->ipmip.ifindex); ipmip_dhcp_option_buffer_append(&pbuf->ipmip4.ipmip.packet, IPMIP_DHCP_SUBOPTCODE_RA_REMOTE_ID, IPMIP4_MSGEXT_SHDR_EXT_SIZE(node->nai), IPMIP4_MSGEXT_SHDR_EXT_DATA(node->nai)); if (ndata->dhcp_server_override != 0) ipmip_dhcp_option_buffer_append(&pbuf->ipmip4.ipmip.packet, IPMIP_DHCP_SUBOPTCODE_RA_SERVER_OVERRIDE, sizeof(Ip_u32), &ndata->dhcp_server_override); ipmip_dhcp_option_buffer_end(&pbuf->ipmip4.ipmip.packet, ra_opt); ipmip_dhcp_option_buffer_close(&pbuf->ipmip4.ipmip.packet); ipmip_dhcp_relay_to_server(&ctx->ipmip4.ipmip, proc, &pbuf->ipmip4.ipmip, pbuf->iff.pub->ifaddr, ndata->dhcp_server); } IP_STATIC int ipmipfa_pmipv4_dhcp_handle_trigger_complete(int event, Ipmipfa_data_t *ctx, Ipmip_proc_t *proc, Ipmipfa_pktbuf_t *pbuf, Ipmipfa_node_t *node) { if (event == IPMIP_TIMER_EVENT_RUN) { if (node != IP_NULL) { Ipmipfa_pmipv4_dhcp_node_data_t *ndata = ipmipfa_node_extension_data(node, &ipmipfa_pmipv4_dhcp); if(IP_NULL == ndata) return IPCOM_ERR_FAILED; if (ndata->dhcp_request) { IPMIP4_EVENT_IF(DEBUG2, proc, ipmip_log_event_add(&ctx->ipmip4.ipmip, proc, "DHCP PMIPv4 Trigger Completed")); ipmipfa_pmipv4_dhcp_relay_forward_server(ctx, proc, ndata->dhcp_request, node, ndata); ipmip_pktbuf_release(&ctx->ipmip4.ipmip, proc, &ndata->dhcp_request->ipmip4.ipmip); ndata->dhcp_request = IP_NULL; } } else { IPMIP4_EVENT_IF(ERR, proc, ipmip_log_event_add(&ctx->ipmip4.ipmip, proc, "DHCP PMIPv4 Trigger Completed -- Unknown Node")); } } /* Free the DHCP packet */ ipmip_pktbuf_release(&ctx->ipmip4.ipmip, proc, &pbuf->ipmip4.ipmip); return IPMIP_TIMER_RET_DONE; } IP_STATIC void ipmipfa_pmipv4_dhcp_ptrq(Ipmipfa_data_t *ctx, Ipmip_proc_t *proc, Ipmipfa_node_t *node, Ipmipfa_pmipv4_dhcp_node_data_t *ndata, Ip_u32 hoa) { Ipmip_buffer_t trigger; Ip_size_t rhdr; Ip_u8 type; /* Populate trigger */ ipmip_buffer_init(&trigger); rhdr = ipmip_attr_hdr_req_create(&trigger, 0, hoa, IPMIP4_CLI_PMIPV4_PTRQ); /**/ type = ipmip4_lla_pmipv4_access_type_from_lladdr_types(node->reginfo.faVisitorMAC->type, node->reginfo.faVisitorMAC->subtype); if (type != 0) ipmip_attr_put_u32(&trigger, IPMIP4_CLI_PMIPV4_ATTR_ACCESS_TYPE, type); if (IPMIP_LLADDR_LEN_LLA(node->reginfo.faVisitorMAC)) { ipmip_attr_put(&trigger, IPMIP4_CLI_PMIPV4_ATTR_INTERFACE_ID, IPMIP_LLADDR_LEN_LLA(node->reginfo.faVisitorMAC), IPMIP_LLADDR_DATA(node->reginfo.faVisitorMAC)); type = ipmip4_lla_pmipv4_device_id_type_from_lladdr_types(node->reginfo.faVisitorMAC->type, node->reginfo.faVisitorMAC->subtype); if (type != 0) { ipmip_attr_put(&trigger, IPMIP4_CLI_PMIPV4_ATTR_DEVICE_ID, IPMIP_LLADDR_LEN_LLA(node->reginfo.faVisitorMAC), IPMIP_LLADDR_DATA(node->reginfo.faVisitorMAC)); ipmip_attr_put_u32(&trigger, IPMIP4_CLI_PMIPV4_ATTR_DEVICE_ID_TYPE, type); } } /* */ ipmip_attr_put_inet(&trigger, IPMIP4_CLI_PMIPV4_ATTR_NFA_COA, node->ifp->iff.ifaddr); ipmip_attr_put_inet(&trigger, IPMIP4_CLI_PMIPV4_ATTR_HOA, hoa); ipmip_attr_put_inet(&trigger, IPMIP4_CLI_PMIPV4_ATTR_HA, ndata->home_agent); ipmip_attr_put(&trigger, IPMIP4_CLI_PMIPV4_ATTR_MN_NAI, IPMIP4_MSGEXT_SHDR_EXT_SIZE(node->nai), IPMIP4_MSGEXT_SHDR_EXT_DATA(node->nai)); ipmip_attr_put_u32(&trigger, IPMIP4_CLI_PMIPV4_ATTR_LIFETIME, node->ifp->lifetime); /**/ if (ndata->mn_ha_spi) ipmip_attr_put_u32(&trigger, IPMIP4_CLI_PMIPV4_ATTR_MN_HA_SPI, ndata->mn_ha_spi); if (ndata->mn_ha_spi_secret.iov_base) ipmip_attr_put(&trigger, IPMIP4_CLI_PMIPV4_ATTR_MN_HA_SPI_SECRET, ndata->mn_ha_spi_secret.iov_len, ndata->mn_ha_spi_secret.iov_base); ipmip_attr_hdr_finalize(&trigger, rhdr); /**/ { Ipmipfa_pmipv4_dhcp_config_ifp_t *conf = ipmipfa_if_extension_data(node->ifp, &ipmipfa_pmipv4_dhcp); if(IP_NULL == conf) goto ret_done; if (ipcom_sendto(conf->udpr.fd, IPMIP_BUFFER_DATA(&trigger), IPMIP_BUFFER_SIZE(&trigger), 0, (struct Ip_sockaddr *)ndata->pmip_client, sizeof(*ndata->pmip_client)) < 0) { IPMIP4_EVENT_IF(ERR, proc, ipmip_log_event_add(&ctx->ipmip4.ipmip, proc, "PMIPv4 UNABLE TO SEND TRIGGER")); } } ret_done: ipmip_buffer_release(&trigger); } IP_STATIC int ipmipfa_pmipv4_dhcp_handle_dhcp(int event, Ipmipfa_data_t *ctx, Ipmip_proc_t *proc, Ipmipfa_pktbuf_t *pbuf, Ipmipfa_node_t *node) { Ipmip_timer_lock_t *lock = IP_NULL; if (event == IPMIP_TIMER_EVENT_RUN) { Ipmip_dhcp_hdr_t *pkt = (Ipmip_dhcp_hdr_t *)IPMIP_BUFFER_PTR(&pbuf->ipmip4.ipmip.packet); Ipmipfa_pmipv4_dhcp_node_data_t *ndata; Ip_u8 *opt = ipmip_dhcp_option_buffer_find(&pbuf->ipmip4.ipmip.packet, IPMIP_DHCP_OPTCODE_DHCP_MESSAGE_TYPE); if (opt == IP_NULL) { IPMIP4_EVENT_IF(ERR, proc, ipmip_log_event_add(&ctx->ipmip4.ipmip, proc, "DHCP %s Received contained no MESSAGE_TYPE", pkt->op == IPMIP_DHCP_OP_BOOTREQUEST? "REQUEST" : "REPLY")); goto done_out; } if (pkt->op == IPMIP_DHCP_OP_BOOTREQUEST) { if (node == IP_NULL) { if (opt[IPMIP_DHCP_OPT_DATA] == IPMIP_DHCP_MSG_DISCOVER || opt[IPMIP_DHCP_OPT_DATA] == IPMIP_DHCP_MSG_REQUEST) { struct Ip_iovec nai; Ipmipfa_pmipv4_dhcp_config_ifp_t *dnode = ipmipfa_if_extension_data(pbuf->iff.priv, &ipmipfa_pmipv4_dhcp); if(IP_NULL == dnode) goto done_out; (void)ipmipfa_pmipv4_dhcp_nai(ctx, proc, dnode, pbuf, &nai); node = ipmipfa_node_create(ctx, proc, pbuf->iff.priv, 0, 0, (Ipmip4_msgext_uhdr_t *)ipmip4_msgext_nai_mn(proc->ntop.ntop_pbuf, nai.iov_base, nai.iov_len), ipmip_lladdr_sanitize(pbuf->iff.pub->ipmip.lladdr, pbuf->ipmip4.ipmip.srcinfo.lladdr)); if (node == IP_NULL) { IPMIP4_EVENT_IF(ERR, proc, ipmip_log_event_add(&ctx->ipmip4.ipmip, proc, "DHCP Discover/Request unable to create node")); goto done_out; } lock = node->lock; /**/ ipmipfa_node_lifetime(ctx, proc, node, IPMIPFA_PENDING_REG_TIMEOUT); node->handler = &ipmipfa_pmipv4_dhcp; /**/ ndata = ipmipfa_node_extension_data(node, &ipmipfa_pmipv4_dhcp); /* Setup information if it is different from the default global configuration */ if (opt[IPMIP_DHCP_OPT_DATA] == IPMIP_DHCP_MSG_REQUEST) goto trigger; } else { IPMIP4_EVENT_IF(ERR, proc, ipmip_log_event_add(&ctx->ipmip4.ipmip, proc, "DHCP state unknown")); goto done_out; } } else { ndata = ipmipfa_node_extension_data(node, &ipmipfa_pmipv4_dhcp); if (!ndata || (ndata->dhcp_server == 0)) { IPMIP4_EVENT_IF(ERR, proc, ipmip_log_event_add(&ctx->ipmip4.ipmip, proc, "DHCP server not specified")); goto done_out; } trigger: if (opt[IPMIP_DHCP_OPT_DATA] == IPMIP_DHCP_MSG_REQUEST && !node->mib.faVisitorRegIsAccepted) { Ip_u32 yiaddr = 0; /* Get the home address */ yiaddr = IP_GET_32ON8(&pkt->yiaddr); if (yiaddr == 0) yiaddr = ipmip_dhcp_option_buffer_find_ip(&pbuf->ipmip4.ipmip.packet, IPMIP_DHCP_OPTCODE_DHCP_REQUESTED_ADDRESS); /* Clear any old */ if (ndata->dhcp_request) ipmip_pktbuf_release(&ctx->ipmip4.ipmip, proc, &ndata->dhcp_request->ipmip4.ipmip); /* Do trigger */ ndata->dhcp_request = pbuf; /* Trigger */ ipmipfa_pmipv4_dhcp_ptrq(ctx, proc, node, ndata, yiaddr); /* Le grande Trigger */ goto unlock_out; } } ipmipfa_pmipv4_dhcp_relay_forward_server(ctx, proc, pbuf, node, ndata); /* We're holding a created node lock? */ } else { if (node == IP_NULL) { IPMIP4_EVENT_IF(ERR, proc, ipmip_log_event_add(&ctx->ipmip4.ipmip, proc, "DHCP Request Reply matched no node")); goto done_out; } if (opt[IPMIP_DHCP_OPT_DATA] == IPMIP_DHCP_MSG_OFFER) { Ip_u32 home_agent = ipmip_dhcp_option_buffer_find_ip(&pbuf->ipmip4.ipmip.packet, IPMIP_DHCP_OPTCODE_HOME_AGENTS); if (home_agent != 0) { /**/ ndata = ipmipfa_node_extension_data(node, &ipmipfa_pmipv4_dhcp); if(IP_NULL == ndata) goto done_out; ndata->home_agent = home_agent; } } ipmip_dhcp_write_to_client(&ctx->ipmip4.ipmip, proc, &pbuf->ipmip4.ipmip, pbuf->iff.pub->ifaddr, &pbuf->iff.pub->ipmip, IP_FALSE); } } done_out: /* Free the DHCP packet */ ipmip_pktbuf_release(&ctx->ipmip4.ipmip, proc, &pbuf->ipmip4.ipmip); unlock_out: if (lock) ipmip_timer_lock_release(&ctx->ipmip4.ipmip, proc, lock); return IPMIP_TIMER_RET_DONE; } IP_STATIC int ipmipfa_pmipv4_dhcp_handle_plt(int event, Ipmipfa_data_t *ctx, Ipmip_proc_t *proc, Ipmip_cli_message_t *request, Ipmipfa_node_t *node) { if (event == IPMIP_TIMER_EVENT_RUN) { struct Ipmip_attr *pattr[IPMIP4_CLI_PMIPV4_ATTR_MAX + 1]; struct Ipmip_attr_header *hdr = (struct Ipmip_attr_header *)IPMIP_BUFFER_DATA(&request->request); Ip_size_t rhdr; Ipmipfa_pmipv4_dhcp_config_ifp_t *cfg = request->opaque; Ipmip_timer_lock_t *lock = IP_NULL; Ipmipfa_pmipv4_dhcp_node_data_t *ndata; ipmip_attr_hdr_parse(IPMIP4_CLI_PMIPV4_ATTR_MAX, hdr, pattr); IPMIP4_EVENT_IF(INFO, proc, ipmip_log_event_add(&ctx->ipmip4.ipmip, proc, "PMIPv4 PLT Trigger Received")); if (node == IP_NULL) { /* Need address description */ const char *ifaddr = ipmip_attr_get_str(pattr[IPMIP4_CLI_PMIPV4_ATTR_IFADDR]); Ipmip_lladdr_t *lladdr; if (ifaddr == IP_NULL) { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&ctx->ipmip4.ipmip, proc, "PMIPv4 PLT lacks Interface Address")); rhdr = ipmip_attr_hdr_err(&request->message, hdr, IP_ERRNO_EINVAL, IP_NULL); goto done_out; } lladdr = ipmip_lladdr_parse(proc, cfg->iff->iff.ipmip.lladdr->type, cfg->iff->iff.ipmip.lladdr->subtype, ifaddr); if (lladdr == IP_NULL) { IPMIP4_EVENT_IF(WARNING, proc, ipmip_log_event_add(&ctx->ipmip4.ipmip, proc, "PMIPv4 PLT unable to parse Interface Address")); rhdr = ipmip_attr_hdr_err(&request->message, hdr, IP_ERRNO_EADDRNOTAVAIL, IP_NULL); goto done_out; } node = ipmipfa_node_create(ctx, proc, cfg->iff, 0, 0, (Ipmip4_msgext_uhdr_t *)ipmip4_msgext_nai_mn(proc->ntop.ntop_pbuf, IPMIP_ATTR_DATA(pattr[IPMIP4_CLI_PMIPV4_ATTR_MN_NAI]), IPMIP_ATTR_PAYLOAD(pattr[IPMIP4_CLI_PMIPV4_ATTR_MN_NAI])), lladdr); if (node == IP_NULL) { IPMIP4_EVENT_IF(ERR, proc, ipmip_log_event_add(&ctx->ipmip4.ipmip, proc, "DHCP Discover unable to create node")); ipcom_free(lladdr); rhdr = ipmip_attr_hdr_err(&request->message, hdr, IP_ERRNO_EADDRNOTAVAIL, IP_NULL); goto done_out; } lock = node->lock; /**/ ipmipfa_node_lifetime(ctx, proc, node, IPMIPFA_PENDING_REG_TIMEOUT * 2); node->handler = &ipmipfa_pmipv4_dhcp; } ndata = ipmipfa_node_extension_data(node, &ipmipfa_pmipv4_dhcp); if(IP_NULL == ndata) return IPCOM_ERR_FAILED; if (pattr[IPMIP4_CLI_PMIPV4_ATTR_DHCP_RELAY_SERVER]) ndata->dhcp_server = ipmip_attr_get_inet(pattr[IPMIP4_CLI_PMIPV4_ATTR_DHCP_RELAY_SERVER]); if (pattr[IPMIP4_CLI_PMIPV4_ATTR_HA]) ndata->home_agent = ipmip_attr_get_inet(pattr[IPMIP4_CLI_PMIPV4_ATTR_HA]); ipmipfa_pmipv4_dhcp_ptrq(ctx, proc, node, ndata, ipmip_attr_get_inet(pattr[IPMIP4_CLI_PMIPV4_ATTR_HOA])); /* If held; release it */ if (lock) ipmip_timer_lock_release(&ctx->ipmip4.ipmip, proc, lock); rhdr = ipmip_attr_hdr_ack(&request->message, hdr); done_out: /* If we have a reply header; terminate it */ ipmip_attr_hdr_finalize(&request->message, rhdr); /* Commit the reply */ ipmip_cli_message_commit(&ctx->ipmip4.ipmip, proc, request); return IPMIP_TIMER_RET_DONE; } else { ipmip_cli_message_free(&ctx->ipmip4.ipmip, proc, request); return IPMIP_TIMER_RET_DONE; } } IP_STATIC int ipmipfa_pmipv4_dhcp_handle(int event, Ipmipfa_data_t *ctx, Ipmip_proc_t *proc, Ipmipfa_pmipv4_dhcp_config_ifp_t *dnode, Ipmipfa_pktbuf_t *pbuf) { if (event == IPMIP_TIMER_EVENT_RUN) { /* */ Ipmip_dhcp_hdr_t *pkt = (Ipmip_dhcp_hdr_t *)IPMIP_BUFFER_PTR(&pbuf->ipmip4.ipmip.packet); struct Ip_iovec nai; /* Store interface pointer */ pbuf->iff.priv = dnode->iff; /* * DEPENDING ON WHAT KIND OF PLATFORM WERE ON, THIS SHOULD PROBABLY BE RESOLVED * USING SOME AUTH CONTEXT? * */ if (ipmipfa_pmipv4_dhcp_nai(ctx, proc, dnode, pbuf, &nai) == IP_FALSE) { IPMIP4_EVENT_IF(ERR, proc, ipmip_log_event_add(&ctx->ipmip4.ipmip, proc, "DHCP %s Received failed to retrieve private data", pkt->op == IPMIP_DHCP_OP_BOOTREQUEST? "REQUEST" : "REPLY")); goto done_out; } IPMIP4_EVENT_IF(DEBUG2, proc, ipmip_log_event_add(&ctx->ipmip4.ipmip, proc, "Processing DHCP request")); /* -- */ ipmipfa_node_findbykey(ctx, proc, dnode->iff, 0, 0, &nai, IP_NULL, &pbuf->ipmip4.ipmip.timeout, (Ipmip_timer_func_t)ipmipfa_pmipv4_dhcp_handle_dhcp, pbuf); return IPMIP_TIMER_RET_DONE; } done_out: /* Free the DHCP packet */ ipmip_pktbuf_release(&ctx->ipmip4.ipmip, proc, &pbuf->ipmip4.ipmip); return IPMIP_TIMER_RET_DONE; } IP_STATIC void ipmipfa_pmipv4_dhcp_reqrep_accepted(struct Ipmipfa_data *ctx, struct Ipmip_proc *proc, void *global_config, Ipmipfa_pmipv4_dhcp_config_ifp_t *ifp_config, Ipmipfa_pmipv4_dhcp_node_data_t *node_config, struct Ipmipfa_node *node, struct Ipmipfa_pktbuf *pbuf) { IPMIP_UNUSED_PARAMETER(ctx); IPMIP_UNUSED_PARAMETER(proc); IPMIP_UNUSED_PARAMETER(global_config); IPMIP_UNUSED_PARAMETER(ifp_config); IPMIP_UNUSED_PARAMETER(node_config); IPMIP_UNUSED_PARAMETER(node); IPMIP_UNUSED_PARAMETER(pbuf); } IP_STATIC void ipmipfa_pmipv4_dhcp_udp_prtq(Ipmipfa_data_t *ctx, Ipmip_proc_t *proc, Ipmipfa_pmipv4_dhcp_config_ifp_t *conf, Ipmipfa_pktbuf_t *pbuf) { struct Ipmip_attr_header *hdr = (struct Ipmip_attr_header *)IPMIP_BUFFER_DATA(&pbuf->ipmip4.ipmip.packet); struct Ipmip_attr *idattr[IPMIP4_CLI_PMIPV4_ATTR_MAX]; struct Ip_iovec nai; ipmip_attr_hdr_parse(IPMIP4_CLI_PMIPV4_ATTR_MAX, hdr, idattr); /**/ if (idattr[IPMIP4_CLI_PMIPV4_ATTR_MN_NAI] == IP_NULL) { IPMIP4_EVENT_IF(ERR, proc, ipmip_log_event_add(&ctx->ipmip4.ipmip, proc, "Received PMIPv4 PRTQ -- missing NAI")); goto done_out; } nai.iov_base = IPMIP_ATTR_DATA(idattr[IPMIP4_CLI_PMIPV4_ATTR_MN_NAI]); nai.iov_len = IPMIP_ATTR_PAYLOAD(idattr[IPMIP4_CLI_PMIPV4_ATTR_MN_NAI]); /**/ ipmipfa_node_findbykey(ctx, proc, conf->iff, 0, 0, &nai, IP_NULL, &pbuf->ipmip4.ipmip.timeout, (Ipmip_timer_func_t)ipmipfa_pmipv4_dhcp_handle_trigger_complete, pbuf); return; done_out: ipmip_pktbuf_release(&ctx->ipmip4.ipmip, proc, &pbuf->ipmip4.ipmip); } IP_STATIC void ipmipfa_pmipv4_dhcp_udp_prrq(Ipmipfa_data_t *ctx, Ipmip_proc_t *proc, Ipmipfa_pmipv4_dhcp_config_ifp_t *conf, Ipmipfa_pktbuf_t *pbuf) { struct Ipmip_attr_header *hdr = (struct Ipmip_attr_header *)IPMIP_BUFFER_DATA(&pbuf->ipmip4.ipmip.packet); struct Ipmip_attr *idattr[IPMIP4_CLI_PMIPV4_ATTR_MAX]; Ipmip_buffer_t prrq; ipmip_attr_hdr_parse(IPMIP4_CLI_PMIPV4_ATTR_MAX, hdr, idattr); /**/ if (idattr[IPMIP4_CLI_PMIPV4_ATTR_MESSAGE] == IP_NULL) { IPMIP4_EVENT_IF(ERR, proc, ipmip_log_event_add(&ctx->ipmip4.ipmip, proc, "Received PMIPv4 PRRQ -- missing message")); goto done_out; } /* Store transport information */ pbuf->rrp_transport = (Ipmipfa_pktbuf_rrp_t)ipmipfa_pmipv4_dhcp_udp_transport; pbuf->rrp_transport_opaque = conf; ipmip_buffer_init(&prrq); ipmip_buffer_append(&prrq, IPMIP_ATTR_DATA(idattr[IPMIP4_CLI_PMIPV4_ATTR_MESSAGE]), IPMIP_ATTR_PAYLOAD(idattr[IPMIP4_CLI_PMIPV4_ATTR_MESSAGE])); ipmip_buffer_assign(&pbuf->ipmip4.ipmip.packet, &prrq); /* Insert */ ipmipfa_reg_recv(ctx, proc, pbuf, IP_NULL); return; done_out: ipmip_pktbuf_release(&ctx->ipmip4.ipmip, proc, &pbuf->ipmip4.ipmip); } IP_STATIC void ipmipfa_pmipv4_dhcp_udp_recvmsg(Ipmipfa_data_t *ctx, Ipmip_proc_t *proc, Ipmipfa_pktbuf_t *pbuf, Ipmipfa_pmipv4_dhcp_config_ifp_t *conf) { struct Ipmip_attr_header *hdr = (struct Ipmip_attr_header *)IPMIP_BUFFER_DATA(&pbuf->ipmip4.ipmip.packet); if (IPMIP_BUFFER_SIZE(&pbuf->ipmip4.ipmip.packet) < sizeof(struct Ipmip_attr_header)) { IPMIP4_EVENT_IF(ERR, proc, ipmip_log_event_add(&ctx->ipmip4.ipmip, proc, "Received PMIPv4 Trigger Message -- Truncated")); goto done_out; } if (IPMIP_ATTR_HDR_ACK(hdr)) { switch (IPMIP_ATTR_HDR_TYPE(hdr)) { case IPMIP4_CLI_PMIPV4_PTRQ: IPMIP4_EVENT_IF(INFO, proc, ipmip_log_event_add(&ctx->ipmip4.ipmip, proc, "Received PMIPv4 PTRP")); ipmipfa_pmipv4_dhcp_udp_prtq(ctx, proc, conf, pbuf); return; } } else { switch (IPMIP_ATTR_HDR_TYPE(hdr)) { case IPMIP4_CLI_PMIPV4_PRRQ: IPMIP4_EVENT_IF(INFO, proc, ipmip_log_event_add(&ctx->ipmip4.ipmip, proc, "Received PMIPv4 PRRQ")); ipmipfa_pmipv4_dhcp_udp_prrq(ctx, proc, conf, pbuf); return; } } done_out: ipmip_pktbuf_release(&ctx->ipmip4.ipmip, proc, &pbuf->ipmip4.ipmip); } IP_STATIC Ip_bool ipmipfa_pmipv4_dhcp_setup(struct Ipmipfa_data *ctx, struct Ipmip_proc *proc, int action, void *global_config, Ipmipfa_pmipv4_dhcp_config_ifp_t *ifp_config, Ipmipfa_pmipv4_dhcp_node_data_t *node_config, struct Ipmipfa_node *node, Ipmip_cli_message_t *request) { IPMIP_UNUSED_PARAMETER(ctx); IPMIP_UNUSED_PARAMETER(proc); IPMIP_UNUSED_PARAMETER(global_config); IPMIP_UNUSED_PARAMETER(ifp_config); IPMIP_UNUSED_PARAMETER(node_config); IPMIP_UNUSED_PARAMETER(node); IPMIP_UNUSED_PARAMETER(request); if (action == IPMIP_CALLBACK_CONFIG_READ) { /* MUST have NAI, MUST be enabled */ if (ifp_config->iff && node->nai != IP_NULL) { node_config->dhcp_server = ifp_config->dhcp_relay_server; node_config->dhcp_server_override = ifp_config->dhcp_relay_server_override; node_config->home_agent = ifp_config->dhcp_home_agent; node_config->mn_ha_spi_secret.iov_base = ifp_config->mn_ha_secretv.iov_base; node_config->mn_ha_spi_secret.iov_len = ifp_config->mn_ha_secretv.iov_len; node_config->mn_ha_spi = ifp_config->mn_ha_spi; node_config->pmip_client = &ifp_config->pmipv4_in; return IP_TRUE; } } else if (action == IPMIP_CALLBACK_CONFIG_FREE) { if (node_config->dhcp_request) ipmip_pktbuf_release(&ctx->ipmip4.ipmip, proc, &node_config->dhcp_request->ipmip4.ipmip); if (node_config->mn_ha_spi_secret.iov_base && node_config->mn_ha_spi_secret.iov_base != ifp_config->mn_ha_secretv.iov_base) ipcom_free(node_config->mn_ha_spi_secret.iov_base); if (node_config->pmip_client && node_config->pmip_client != &ifp_config->pmipv4_in) ipcom_free(node_config->pmip_client); } else if (action == IPMIP_CALLBACK_CONFIG_DUMP) { } return IP_FALSE; } IP_STATIC void ipmipfa_pmipv4_dhcp_config(struct Ipmipfa_data *ctx, struct Ipmip_proc *proc, int action, struct Ipmipfa_iff *ifp, void *gcfg, Ipmipfa_pmipv4_dhcp_config_ifp_t *cfg, Ipmip_cli_message_t *request) { IPMIP_UNUSED_PARAMETER(ctx); IPMIP_UNUSED_PARAMETER(proc); IPMIP_UNUSED_PARAMETER(gcfg); IPMIP_UNUSED_PARAMETER(request); if (action == IPMIP_CALLBACK_CONFIG_READ) { cfg->udpr.fd = IP_INVALID_SOCKET; if (ipmip_sysvar_bool(ipmip_sysvar_bool(IP_FALSE, "ipmipfa.pmipv4.dhcp.enable"), "ipmipfa.if.%s.pmipv4.dhcp.enable", ifp->iff.ipmip.ifname)) { ipcom_memset(&cfg->pmipv4_in, 0, sizeof(cfg->pmipv4_in)); cfg->pmipv4_in.sin_family = IP_AF_INET; IPCOM_SA_LEN_SET(&cfg->pmipv4_in, sizeof(cfg->pmipv4_in)); /**/ cfg->port = ipmip_sysvar_ulong(ipmip_sysvar_ulong(0, "ipmipfa.pmipv4.dhcp.port"), "ipmipfa.if.%s.pmipv4.dhcp.port", ifp->iff.ipmip.ifname); cfg->pmipv4_in.sin_port = ipcom_htons(ipmip_sysvar_ulong(ipmip_sysvar_ulong(IPMIP4_PORT, "ipmipfa.pmipv4.dhcp.client.port"), "ipmipfa.if.%s.pmipv4.dhcp.client.port", ifp->iff.ipmip.ifname)); if (!ipmip_sysvar_inet(0, &cfg->dhcp_relay_server_override, IP_NULL, "ipmipfa.if.%s.pmipv4.dhcp.relay.server.override", ifp->iff.ipmip.ifname)) ipmip_sysvar_inet(0, &cfg->dhcp_relay_server_override, IP_NULL, "ipmipfa.pmipv4.dhcp.relay.server.override"); if (!ipmip_sysvar_inet(ip_htonl(IP_INADDR_LOOPBACK), &cfg->pmipv4_in.sin_addr.s_addr, IP_NULL, "ipmipfa.if.%s.pmipv4.dhcp.client.address", ifp->iff.ipmip.ifname)) ipmip_sysvar_inet(ip_htonl(IP_INADDR_LOOPBACK), &cfg->pmipv4_in.sin_addr.s_addr, IP_NULL, "ipmipfa.pmipv4.dhcp.client.address"); if (!ipmip_sysvar_inet(0, &cfg->dhcp_relay_server, IP_NULL, "ipmipfa.if.%s.pmipv4.dhcp.relay.server", ifp->iff.ipmip.ifname)) ipmip_sysvar_inet(0, &cfg->dhcp_relay_server, IP_NULL, "ipmipfa.pmipv4.dhcp.relay.server"); if (!ipmip_sysvar_inet(cfg->dhcp_relay_server, &cfg->dhcp_home_agent, IP_NULL, "ipmipfa.if.%s.pmipv4.dhcp.home.agent", ifp->iff.ipmip.ifname)) ipmip_sysvar_inet(cfg->dhcp_relay_server, &cfg->dhcp_home_agent, IP_NULL, "ipmipfa.pmipv4.dhcp.home.agent"); cfg->mn_ha_spi = ipmip_sysvar_ulong(ipmip_sysvar_ulong(0, "ipmipfa.pmipv4.dhcp.spi.mn.ha"), "ipmipfa.if.%s.pmipv4.dhcp.spi.mn.ha", ifp->iff.ipmip.ifname); if ((cfg->mn_ha_secretv.iov_base = ipmip_sysvar("ipmipfa.if.%s.pmipv4.dhcp.spi.mn.ha.secret", ifp->iff.ipmip.ifname)) == IP_NULL) cfg->mn_ha_secretv.iov_base = ipmip_sysvar("ipmipfa.pmipv4.dhcp.spi.mn.ha.secret"); if (cfg->mn_ha_secretv.iov_base) cfg->mn_ha_secretv.iov_len = ipcom_strlen(cfg->mn_ha_secretv.iov_base); cfg->domain = ipmip_sysvar("ipmipfa.if.%s.pmipv4.dhcp.domain", ifp->iff.ipmip.ifname); if (cfg->domain == IP_NULL) cfg->domain = ipmip_sysvar("ipmipfa.pmipv4.dhcp.domain"); if (cfg->domain == IP_NULL) cfg->domain = ipcom_strdup("unknown.com"); ipcom_memset(&cfg->sin4, 0, sizeof(cfg->sin4)); cfg->sin4.sin_family = IP_AF_INET; IPCOM_SA_LEN_SET(&cfg->sin4, sizeof(cfg->sin4)); cfg->sin4.sin_addr.s_addr = ifp->iff.ifaddr; cfg->sin4.sin_port = ip_htons(cfg->port); cfg->udpr.udp_callback = (Ipmip4_pkt_udp_cb_t)ipmipfa_pmipv4_dhcp_udp_recvmsg; cfg->udpr.opaque = cfg; cfg->udpr.fd = ipmip_inet_udp_socket(&cfg->sin4); if (cfg->udpr.fd != IP_INVALID_SOCKET) ipmip4_pkt_udp_register(&ctx->ipmip4, proc, &cfg->udpr); cfg->iff = ifp; ipmip_dhcp_context_create(&ctx->ipmip4.ipmip, proc); /* Register the base handle */ cfg->dhcp.ifindex = ifp->iff.ipmip.ifindex; cfg->dhcp.lock = ifp->if_lock; cfg->dhcp.opaque = cfg; cfg->dhcp.process_func = (Ipmip_timer_func_t)ipmipfa_pmipv4_dhcp_handle; ipmip_dhcp_register(&ctx->ipmip4.ipmip, proc, &cfg->dhcp); /* Start ARP? */ if (ifp->iff.ipmip.lladdr != IP_NULL && ifp->iff.ipmip.lladdr->type == IPMIP_LLADDR_TYPE_MAC) { cfg->arp.ifindex = ifp->iff.ipmip.ifindex; cfg->arp.lock = ifp->if_lock; cfg->arp.opaque = cfg; cfg->arp.process_func = (Ipmip_timer_func_t)ipmipfa_pmipv4_dhcp_arp; ipmip_inet_arp_context_in_create(&ctx->ipmip4.ipmip, proc); ipmip_inet_arp_context_out_create(&ctx->ipmip4.ipmip, proc); ipmip_inet_arp_register(&ctx->ipmip4.ipmip, proc, &cfg->arp); } if (cfg->dhcp_relay_server_override) { int ret; if ((ret = ipmip_netlink_inX_addr(&ctx->ipmip4.ipmip, proc, IP_AF_INET, IP_RTM_NEWADDR, ifp->iff.ipmip.ifindex, &cfg->dhcp_relay_server_override, 32, 0, 0)) != 0) { if (ret != -IP_ERRNO_EEXIST) { /* */ IPMIP4_EVENT_IF(ERR, proc, ipmip_log_event_add(&ctx->ipmip4.ipmip, proc, "Foreign Agent PMIPv4 DHCP interface %s unable to add Proxy DHCP Gateway address %s", ifp->iff.ipmip.ifname, ipmip_ntop_inet(proc, cfg->dhcp_relay_server_override))); } } } } } else if (action == IPMIP_CALLBACK_CONFIG_FREE) { if (cfg->iff) { ipmip4_pkt_udp_unregister(&ctx->ipmip4, proc, &cfg->udpr); if (cfg->domain) ipcom_free(cfg->domain); if (cfg->udpr.fd != IP_INVALID_SOCKET) ipcom_socketclose(cfg->udpr.fd); if (cfg->mn_ha_secretv.iov_base) ipcom_free(cfg->mn_ha_secretv.iov_base); ipmip_inet_arp_unregister(&ctx->ipmip4.ipmip, proc, &cfg->arp); if (cfg->dhcp_relay_server_override) { ipmip_netlink_inX_addr(&ctx->ipmip4.ipmip, proc, IP_AF_INET, IP_RTM_DELADDR, ifp->iff.ipmip.ifindex, &cfg->dhcp_relay_server_override, 32, 0, 0); } } /**/ cfg->iff = IP_NULL; cfg->domain = IP_NULL; cfg->udpr.fd = IP_INVALID_SOCKET; cfg->mn_ha_secretv.iov_base = IP_NULL; } else if (action == IPMIP_CALLBACK_CONFIG_DUMP) { /* Could dump, but dont bother */ if (cfg->iff != IP_NULL) { ipmip_cli_config_printf(&request->message, "ipmipfa.if.%s.pmipv4.dhcp.enable=enabled", ifp->iff.ipmip.ifname); ipmip_cli_config_printf(&request->message, "ipmipfa.if.%s.pmipv4.dhcp.port=%d", ifp->iff.ipmip.ifname, cfg->port); ipmip_cli_config_printf(&request->message, "ipmipfa.if.%s.pmipv4.dhcp.relay.server=%s", ifp->iff.ipmip.ifname, ipmip_ntop_inet(proc, cfg->dhcp_relay_server)); ipmip_cli_config_printf(&request->message, "ipmipfa.if.%s.pmipv4.dhcp.relay.server.override=%s", ifp->iff.ipmip.ifname, ipmip_ntop_inet(proc, cfg->dhcp_relay_server_override)); ipmip_cli_config_printf(&request->message, "ipmipfa.if.%s.pmipv4.dhcp.server.proxy_address=%s", ifp->iff.ipmip.ifname, ipmip_ntop_inet(proc, cfg->dhcp_proxy_address)); ipmip_cli_config_printf(&request->message, "ipmipfa.if.%s.pmipv4.dhcp.home.agent=%s", ifp->iff.ipmip.ifname, ipmip_ntop_inet(proc, cfg->dhcp_home_agent)); ipmip_cli_config_printf(&request->message, "ipmipfa.if.%s.pmipv4.dhcp.domain=%s", ifp->iff.ipmip.ifname, cfg->domain); ipmip_cli_config_printf(&request->message, "ipmipfa.if.%s.pmipv4.dhcp.client.port=%d", ifp->iff.ipmip.ifname, ip_ntohs(cfg->pmipv4_in.sin_port)); ipmip_cli_config_printf(&request->message, "ipmipfa.if.%s.pmipv4.dhcp.client.address=%s", ifp->iff.ipmip.ifname, ipmip_ntop_inet(proc, cfg->pmipv4_in.sin_addr.s_addr)); ipmip_cli_config_printf(&request->message, "ipmipfa.if.%s.pmipv4.dhcp.spi.mn.ha=%u", ifp->iff.ipmip.ifname, cfg->mn_ha_spi); if (cfg->mn_ha_secretv.iov_base) ipmip_cli_config_printf(&request->message, "ipmipfa.if.%s.pmipv4.dhcp.spi.mn.ha.secret=%s", ifp->iff.ipmip.ifname, cfg->mn_ha_secretv.iov_base); } else { ipmip_cli_config_printf(&request->message, "ipmipfa.if.%s.pmipv4.dhcp.enable=disabled", ifp->iff.ipmip.ifname); } } } IP_STATIC Ip_bool ipmipfa_pmipv4_dhcp_attr(struct Ipmipfa_data *ctx, struct Ipmip_proc *proc, struct Ipmipfa_iff *ifp, void *gcfg, Ipmipfa_pmipv4_dhcp_config_ifp_t *cfg, Ipmip_cli_message_t *request) { struct Ipmip_attr_header *hdr = (struct Ipmip_attr_header *)IPMIP_BUFFER_DATA(&request->request); Ip_size_t rhdr; IPMIP_UNUSED_PARAMETER(ctx); IPMIP_UNUSED_PARAMETER(proc); IPMIP_UNUSED_PARAMETER(gcfg); /* */ switch (IPMIP_ATTR_HDR_TYPE(hdr)) { case IPMIP4_CLI_PMIPV4_PLT: { const char *name; struct Ipmip_attr *nai; /* Correct handler? */ name = ipmip_attr_hdr_find_str(hdr, IPMIP4_CLI_PMIPV4_ATTR_HANDLER); if (name != IP_NULL && ipcom_strcasecmp(name, IPMIPFA_REGEXT_PMIPV4_DHCP) != 0) return IP_FALSE; /* Correct interface? */ name = ipmip_attr_hdr_find_str(hdr, IPMIP4_CLI_PMIPV4_ATTR_IFNAME); if (name != IP_NULL && ipcom_strcasecmp(name, ifp->iff.ipmip.ifname) != 0) return IP_FALSE; nai = ipmip_attr_hdr_find(hdr, IPMIP4_CLI_PMIPV4_ATTR_MN_NAI); if (nai == IP_NULL) rhdr = ipmip_attr_hdr_err(&request->message, hdr, IP_ERRNO_EINVAL, IP_NULL); else { struct Ip_iovec naiv; /* Store the interface config */ request->opaque = cfg; naiv.iov_base = IPMIP_ATTR_DATA(nai); naiv.iov_len = IPMIP_ATTR_PAYLOAD(nai); /**/ ipmipfa_node_findbykey(ctx, proc, ifp, 0, 0, &naiv, IP_NULL, &request->timer, (Ipmip_timer_func_t)ipmipfa_pmipv4_dhcp_handle_plt, request); return IP_TRUE; } /* If we have a reply header; terminate it */ ipmip_attr_hdr_finalize(&request->message, rhdr); /* Commit the reply */ ipmip_cli_message_commit(&ctx->ipmip4.ipmip, proc, request); } return IP_TRUE; } return IP_FALSE; } /* **************************************************************************** * 10 GLOBAL FUNCTIONS **************************************************************************** */ IP_GLOBAL void ipmipfa_pmipv4_dhcp_install(void); IP_GLOBAL void ipmipfa_pmipv4_dhcp_install(void) { ipcom_memset(&ipmipfa_pmipv4_dhcp, 0, sizeof(ipmipfa_pmipv4_dhcp)); ipmipfa_pmipv4_dhcp.name = IPMIPFA_REGEXT_PMIPV4_DHCP; ipmipfa_pmipv4_dhcp.ifp_data_size = sizeof(Ipmipfa_pmipv4_dhcp_config_ifp_t); ipmipfa_pmipv4_dhcp.node_data_size = sizeof(Ipmipfa_pmipv4_dhcp_node_data_t); ipmipfa_pmipv4_dhcp.config_ifp = (Ipmipfa_extension_config_ifp_t)ipmipfa_pmipv4_dhcp_config; ipmipfa_pmipv4_dhcp.attr_ifp = (Ipmipfa_extension_attr_ifp_t)ipmipfa_pmipv4_dhcp_attr; ipmipfa_pmipv4_dhcp.setup = (Ipmipfa_extension_setup_t)ipmipfa_pmipv4_dhcp_setup; ipmipfa_pmipv4_dhcp.pkt_reqrep_accepted = (Ipmipfa_extension_pkt_reqrep_accepted_t)ipmipfa_pmipv4_dhcp_reqrep_accepted; ipmipfa_pmipv4_dhcp.revoke_inform = (Ipmipfa_extension_revoke_inform_t)ipmipfa_pmipv4_dhcp_revoke_inform; ipmipfa_context_register_extension(&ipmipfa_pmipv4_dhcp, IPMIPFA_FUNCTION_REGEXT); } /* **************************************************************************** * 11 PUBLIC FUNCTIONS **************************************************************************** */ /* **************************************************************************** * END OF FILE **************************************************************************** */