1348 lines
57 KiB
C
1348 lines
57 KiB
C
|
|
/*
|
|
******************************************************************************
|
|
* 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 <joel.hortelis@interpeak.se>
|
|
******************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 1 DESCRIPTION
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 2 CONFIGURATION
|
|
****************************************************************************
|
|
*/
|
|
|
|
#include "ipmipfa_config.h"
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 3 INCLUDE FILES
|
|
****************************************************************************
|
|
*/
|
|
#define IPCOM_USE_CLIB_PROTO
|
|
#include <ipcom_clib.h>
|
|
#include <ipcom_os.h>
|
|
#include <ipcom_sock.h>
|
|
#include <ipcom_sock6.h>
|
|
#include <ipcom_inet.h>
|
|
#include <ipcom_list.h>
|
|
#include <ipcom_hash.h>
|
|
#include <ipcom_err.h>
|
|
#include <ipcom_sysvar.h>
|
|
#include <ipcom_syslog.h>
|
|
#include <ipcom_shell.h>
|
|
#include <ipcom_route.h>
|
|
|
|
#include <ipmip.h>
|
|
#include <private/ipmip_util.h>
|
|
#include <private/ipmip_sysvar.h>
|
|
#include <private/ipmip_inet.h>
|
|
#include <private/ipmip_dhcp.h>
|
|
|
|
#include <ipmip4.h>
|
|
#include <private/ipmip4_context.h>
|
|
#include <private/ipmip4_util.h>
|
|
#include <private/ipmip4_sysext.h>
|
|
#include <private/ipmip4_cli.h>
|
|
#include <private/ipmip4_pkt.h>
|
|
|
|
#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
|
|
****************************************************************************
|
|
*/
|