#include "fsm.h"
#include <stdlib.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/queue.h>
#include "var.h"
#include "misc.h"
#include "session.h"
#include "isakmp.h"
#include "ike_session.h"
#include "isakmp_var.h"
#include "isakmp_ident.h"
#include "isakmp_agg.h"
#include "isakmp_quick.h"
#include "isakmp_inf.h"
#include "vpn_control_var.h"
#include "plog.h"
#include "schedule.h"
void
fsm_set_state(int *var, int state)
{
*var = state;
plog(ASL_LEVEL_NOTICE, "state changed to: %s\n", s_isakmp_state(0, 0, state));
}
void
fsm_api_handle_connect (struct sockaddr_storage *remote, const int connect_mode)
{
}
void
fsm_api_handle_disconnect (struct sockaddr_storage *remote, const char *reason)
{
}
void
fsm_pfkey_handle_acquire (phase2_handle_t *iph2)
{
}
void
fsm_pfkey_getspi_complete (phase2_handle_t *iph2)
{
}
void
fsm_isakmp_initial_pkt (vchar_t *pkt, struct sockaddr_storage *local, struct sockaddr_storage *remote)
{
}
int
fsm_ikev1_phase1_process_payloads (phase1_handle_t *iph1, vchar_t *msg)
{
int error = 0;
#ifdef ENABLE_STATS
struct timeval start, end;
gettimeofday(&start, NULL);
#endif
switch (iph1->status) {
case IKEV1_STATE_PHASE1_ESTABLISHED:
return 0;
case IKEV1_STATE_IDENT_I_MSG1SENT:
error = ident_i2recv(iph1, msg);
break;
case IKEV1_STATE_IDENT_I_MSG3SENT:
error = ident_i4recv(iph1, msg);
break;
case IKEV1_STATE_IDENT_I_MSG5SENT:
error = ident_i6recv(iph1, msg);
break;
case IKEV1_STATE_IDENT_R_START:
error = ident_r1recv(iph1, msg);
if (error) {
plog(ASL_LEVEL_ERR, "failed to pre-process packet.\n");
goto fail;
}
break;
case IKEV1_STATE_IDENT_R_MSG2SENT:
error = ident_r3recv(iph1, msg);
break;
case IKEV1_STATE_IDENT_R_MSG4SENT:
error = ident_r5recv(iph1, msg);
break;
case IKEV1_STATE_AGG_R_START:
error = agg_r1recv(iph1, msg);
if (error) {
plog(ASL_LEVEL_ERR, "failed to pre-process packet.\n");
goto fail;
}
break;
case IKEV1_STATE_AGG_I_MSG1SENT:
error = agg_i2recv(iph1, msg);
break;
case IKEV1_STATE_AGG_R_MSG2SENT:
error = agg_r3recv(iph1, msg);
break;
default:
error = -1;
break;
}
if (error)
return 0;
VPTRINIT(iph1->sendbuf);
SCHED_KILL(iph1->scr);
plog(ASL_LEVEL_DEBUG, "===\n");
if ((error = fsm_ikev1_phase1_send_response(iph1, msg))) {
plog(ASL_LEVEL_ERR, "failed to process packet.\n");
goto fail;
}
#ifdef ENABLE_STATS
gettimeofday(&end, NULL);
syslog(LOG_NOTICE, "%s(%s): %8.6f",
"Phase 1", s_isakmp_state(iph1->etype, iph1->side, iph1->status),
timedelta(&start, &end));
#endif
if (FSM_STATE_IS_ESTABLISHED(iph1->status))
ikev1_phase1_established(iph1);
return 0;
fail:
plog(ASL_LEVEL_ERR, "Phase 1 negotiation failed.\n");
ike_session_unlink_phase1(iph1);
return error;
}
int
fsm_ikev1_phase1_send_response(phase1_handle_t *iph1, vchar_t *msg)
{
int error = 0;
switch (iph1->status) {
case IKEV1_STATE_IDENT_I_START:
error = ident_i1send(iph1, msg);
break;
case IKEV1_STATE_IDENT_I_MSG2RCVD:
error = ident_i3send(iph1, msg);
break;
case IKEV1_STATE_IDENT_I_MSG4RCVD:
error = ident_i5send(iph1, msg);
break;
case IKEV1_STATE_IDENT_I_MSG6RCVD:
error = ident_ifinalize(iph1, msg);
break;
case IKEV1_STATE_IDENT_R_MSG1RCVD:
error = ident_r2send(iph1, msg);
break;
case IKEV1_STATE_IDENT_R_MSG3RCVD:
error = ident_r4send(iph1, msg);
break;
case IKEV1_STATE_IDENT_R_MSG5RCVD:
error = ident_r6send(iph1, msg);
break;
case IKEV1_STATE_AGG_I_START:
error = agg_i1send(iph1, msg);
break;
case IKEV1_STATE_AGG_I_MSG2RCVD:
error = agg_i3send(iph1, msg);
break;
case IKEV1_STATE_AGG_R_MSG1RCVD:
error = agg_r2send(iph1, msg);
break;
case IKEV1_STATE_AGG_R_MSG3RCVD:
error = agg_rfinalize(iph1, msg);
break;
default:
error = -1;
break;;
}
if (error) {
vpncontrol_notify_ike_failed(error, FROM_LOCAL, iph1_get_remote_v4_address(iph1), 0, NULL);
}
return error;
}
int
fsm_ikev1_phase2_process_payloads (phase2_handle_t *iph2, vchar_t *msg)
{
int error = 0;
#ifdef ENABLE_STATS
struct timeval start, end;
gettimeofday(&start, NULL);
#endif
switch (iph2->status) {
case IKEV1_STATE_PHASE2_ESTABLISHED:
case IKEV1_STATE_QUICK_I_GETSPISENT:
case IKEV1_STATE_QUICK_R_GETSPISENT:
return 0;
case IKEV1_STATE_QUICK_I_MSG1SENT:
error = quick_i2recv(iph2, msg);
break;
case IKEV1_STATE_QUICK_I_MSG3SENT:
error = quick_i4recv(iph2, msg);
break;
case IKEV1_STATE_QUICK_R_START:
error = quick_r1recv(iph2, msg);
break;
case IKEV1_STATE_QUICK_R_MSG2SENT:
error = quick_r3recv(iph2, msg);
break;
default:
error = -1;
break;
}
if (error) {
plog(ASL_LEVEL_ERR, "failed to pre-process packet.\n");
if (error == ISAKMP_INTERNAL_ERROR)
fatal_error(-1);
isakmp_info_send_n1(iph2->ph1, error, NULL);
goto fail;
}
if (iph2->sendbuf == NULL && iph2->status != IKEV1_STATE_QUICK_R_MSG1RCVD) {
plog(ASL_LEVEL_ERR,
"no buffer found as sendbuf\n");
error = -1;
goto fail;
}
VPTRINIT(iph2->sendbuf);
SCHED_KILL(iph2->scr);
if (iph2->status == IKEV1_STATE_QUICK_I_ADDSA)
return 0;
error = fsm_ikev1_phase2_send_response(iph2, msg);
if (error) {
plog(ASL_LEVEL_ERR, "failed to process packet.\n");
goto fail;
}
#ifdef ENABLE_STATS
gettimeofday(&end, NULL);
syslog(LOG_NOTICE, "%s(%s): %8.6f",
"Phase 2",
s_isakmp_state(ISAKMP_ETYPE_QUICK, iph2->side, iph2->status),
timedelta(&start, &end));
#endif
return 0;
fail:
plog(ASL_LEVEL_ERR, "Phase 2 negotiation failed.\n");
ike_session_unlink_phase2(iph2);
return error;
}
int
fsm_ikev1_phase2_send_response(phase2_handle_t *iph2, vchar_t *msg)
{
int error = 0;
switch (iph2->status) {
case IKEV1_STATE_QUICK_R_MSG1RCVD:
error = quick_rprep(iph2, msg);
break;
case IKEV1_STATE_QUICK_I_GETSPIDONE:
error = quick_i1send(iph2, msg);
break;
case IKEV1_STATE_QUICK_I_MSG2RCVD:
error = quick_i3send(iph2, msg);
break;
case IKEV1_STATE_QUICK_R_GETSPIDONE:
error = quick_r2send(iph2, msg);
break;
case IKEV1_STATE_QUICK_R_MSG3RCVD:
error = quick_r4send(iph2, msg);
break;
case IKEV1_STATE_QUICK_R_COMMIT:
error = quick_rfinalize(iph2, msg);
break;
default:
error = -1;
break;;
}
return error;
}