#define MAX_CONNECTIONS 16
typedef struct {
- bool valid; // used or not
- char *name; // connection name
- uint64_t signal; // local signal
- int notify; // notify value
- int tmval; // backoff timer value
+ bool valid; // used or not
+ char *name; // connection name
+ uint64_t signal; // local signal
+ int notify; // failure notify value
+ void *container; // additional data
} alerts_status_t;
static alerts_status_t g_alerts_status[MAX_CONNECTIONS];
return 0;
}
-int get_alerts_timer(int index)
+void *get_alerts_vendor_container(int index)
{
- if ((index < 0) || (index >= MAX_CONNECTIONS)) return 0;
+ if ((index < 0) || (index >= MAX_CONNECTIONS)) return NULL;
if (g_alerts_status[index].valid)
{
- return g_alerts_status[index].tmval;
+ return g_alerts_status[index].container;
}
- return 0;
+ return NULL;
}
int get_alerts_index(char *name)
g_alerts_status[i].name = strdup(name);
g_alerts_status[i].signal = 0;
g_alerts_status[i].notify = 0;
- g_alerts_status[i].tmval = 0;
+ g_alerts_status[i].container = NULL;
g_alerts_status[i].valid = TRUE;
return i;
}
g_alerts_status[i].signal = g_alerts_status[i].signal | alert_bit;
if (alert == ALERT_NETWORK_FAILURE)
{
- g_alerts_status[i].notify = va_arg(args,int);
- g_alerts_status[i].tmval = va_arg(args, int);
+ g_alerts_status[i].notify = va_arg(args, int);
+ g_alerts_status[i].container = va_arg(args, void*);
}
DBG1(DBG_CFG, "Alert for event initiated by service notify: %d, signal %"PRIu64"", g_alerts_status[i].notify, g_alerts_status[i].signal);
return;
int get_alerts_index(char *name);
void free_alerts_index(int index);
int get_alerts_notify(int index);
-int get_alerts_timer(int index);
+void *get_alerts_vendor_container(int index);
charon_error_code_t get_error_from_alerts(int index);
void set_alert(ike_sa_t *ike_sa, alert_t alert, va_list args);
{
charon_response_t *res = create_response_msg(RES_INITIATE);
charon_error_code_t error = get_error_from_alerts(index);
+ linked_list_t *list = NULL;
int notify = 0;
- int tmval = 0;
if (error == CHARON_ERR_NETWORK_FAILURE)
{
notify = get_alerts_notify(index);
- tmval = get_alerts_timer(index);
+ list = get_alerts_vendor_container(index);
}
free_alerts_index(index);
push_string(&res, initiate.name, msg->initiate.name);
res->initiate.status = error;
res->initiate.notify = notify;
- res->initiate.tmval = tmval;
+
+ if (list)
+ {
+ vendor_response_data_t *data;
+ int length = 0;
+
+ enumerator_t *enumerator = list->create_enumerator(list);
+ while (enumerator->enumerate(enumerator, &data))
+ {
+ length += data->get_length(data);
+ }
+ enumerator->destroy(enumerator);
+ if (length > 0)
+ {
+ char *mem = calloc(length + sizeof(int), 1);
+ char *tmp = mem + sizeof(int);
+
+ *((unsigned int*)mem) = length;
+
+ while (list->remove_first(list, &data) == SUCCESS)
+ {
+ tmp = data->pack(data, tmp);
+ data->destroy(data);
+ }
+ push_array(&res, initiate.notifies, mem, length + sizeof(int));
+ free(mem);
+ }
+ list->destroy(list);
+ }
+
fwrite(res, 1, res->length, msg->out);
free(res);
}
+static char* get_notifies(ike_sa_t *ike_sa, int *total)
+{
+ linked_list_t *vendor_notifies = linked_list_create();
+ int length = ike_sa->get_vendor_notifies(ike_sa, vendor_notifies);
+
+ if (length)
+ {
+ vendor_response_data_t *notify;
+
+ char *mem = calloc(length + sizeof(int), 1);
+ char *tmp = mem + sizeof(int);
+
+ *((unsigned int*)mem) = length;
+
+ while (vendor_notifies->remove_first(vendor_notifies, ¬ify) == SUCCESS)
+ {
+ tmp = notify->pack(notify, tmp);
+ notify->destroy(notify);
+ }
+ vendor_notifies->destroy(vendor_notifies);
+
+ *total = length + sizeof(int);
+ return mem;
+ }
+ vendor_notifies->destroy(vendor_notifies);
+ return NULL;
+}
+
static char* get_attributes(ike_sa_t *ike_sa, int *total)
{
linked_list_t *vendor_attributes = linked_list_create();
{
if (streq(msg->initiate.name, ike_sa->get_name(ike_sa)))
{
- char *attr = NULL;
+ char *data = NULL;
int length = 0;
push_string(&res, initiate.device, ike_sa->get_tun_name(ike_sa));
res->initiate.mtu = ike_sa->get_mtu(ike_sa);
/* Addresses */
- attr = get_addresses(ike_sa, 4);
- if (attr)
+ data = get_addresses(ike_sa, 4);
+ if (data)
{
- push_string(&res, initiate.address, attr);
- free(attr);
+ push_string(&res, initiate.address, data);
+ free(data);
}
/* attributes */
- attr = get_attributes(ike_sa, &length);
- if (attr)
+ data = get_attributes(ike_sa, &length);
+ if (data)
+ {
+ push_array(&res, initiate.attributes, data, length);
+ free(data);
+ }
+
+ /* notifies */
+ data = get_notifies(ike_sa, &length);
+ if (data)
{
- push_array(&res, initiate.attributes, attr, length);
- free(attr);
+ push_array(&res, initiate.notifies, data, length);
+ free(data);
}
/* end */
char *name;
charon_error_code_t status;
int notify;
- int tmval;
char *device;
char *address;
char *attributes;
return this->type;
}
+METHOD(vendor_request_data_t, get_notify_type, notify_type_t,
+ private_vendor_request_data_t *this)
+{
+ return this->type;
+}
+
METHOD(vendor_request_data_t, get_data, chunk_t,
private_vendor_request_data_t *this)
{
INIT(this,
.public = {
.get_attribute_type = _get_attribute_type,
+ .get_notify_type = _get_notify_type,
.get_data = _get_data,
.is_empty = _is_empty,
.destroy = _destroy,
INIT(this,
.public = {
.get_attribute_type = _get_attribute_type,
+ .get_notify_type = _get_notify_type,
.get_data = _get_data,
.is_empty = _is_empty,
.destroy = _destroy,
}
if (!host->is_anyaddr(host))
{
- this->data = host->get_address(host);
+ chunk_t chunk = host->get_address(host);
+ this->data = chunk_clone(chunk);
}
return &this->public;
/* get configuration type */
configuration_attribute_type_t (*get_attribute_type)(vendor_request_data_t *this);
+ /* get notify type */
+ notify_type_t (*get_notify_type)(vendor_request_data_t *this);
+
/* return vendor data */
chunk_t (*get_data)(vendor_request_data_t *this);
unsigned int *values;
};
+METHOD(vendor_request_list_t, is_requested, bool,
+ private_vendor_request_list_t *this, int type)
+{
+ if (this->size)
+ {
+ for (int i = 0; i < this->size; i++)
+ {
+ if (this->values[i] == type)
+ {
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
METHOD(vendor_request_list_t, get_next, int,
private_vendor_request_list_t *this)
{
INIT(this,
.public = {
+ .is_requested = _is_requested,
.get_next = _get_next,
.reset = _reset,
.destroy = _destroy,
typedef struct vendor_request_list_t vendor_request_list_t;
struct vendor_request_list_t {
+ /* check if requested */
+ bool (*is_requested)(vendor_request_list_t *this, int type);
+
/* get next request value */
int (*get_next)(vendor_request_list_t *this);
METHOD(vendor_response_data_t, destroy, void,
private_vendor_response_data_t *this)
{
+ if (this->data.ptr)
+ {
+ chunk_free(&this->data);
+ }
free(this);
}
.destroy = _destroy,
},
.type = type,
- .data = data,
+ .data = chunk_clone(data),
);
return &this->public;
}
#include <utils/identification.h>
#ifdef VOWIFI_CFG
+#include "vendor_request_data.h"
#include "vendor_request_list.h"
#endif
* configuration attributes requested by service
*/
vendor_request_list_t *attributes_list;
+
+ /**
+ * Vendor notifies request list
+ *
+ * Notifies requested by service
+ */
+ linked_list_t *notifies_request_list;
+
+ /**
+ * Vendor notifies response list
+ *
+ * Notifies expected in response by service
+ */
+ vendor_request_list_t *notifies_response_list;
#endif
};
{
this->dpd = interval;
}
+
+METHOD(peer_cfg_t, add_vendor_notifies_request_list, void,
+ private_peer_cfg_t *this, char *buffer)
+{
+ if (buffer)
+ {
+ this->notifies_response_list = build_vendor_request_list(buffer);
+ }
+}
+
+METHOD(peer_cfg_t, is_vendor_notify_requested, bool,
+ private_peer_cfg_t *this, int type)
+{
+ if (this->notifies_response_list)
+ {
+ return this->notifies_response_list->is_requested(this->notifies_response_list, type);
+ }
+ return FALSE;
+}
+
+METHOD(peer_cfg_t, get_next_vendor_notify_request, int,
+ private_peer_cfg_t *this)
+{
+ if (this->notifies_response_list)
+ {
+ return this->notifies_response_list->get_next(this->notifies_response_list);
+ }
+ return 0;
+}
+
+METHOD(peer_cfg_t, rewind_vendor_notify_request_list, void,
+ private_peer_cfg_t *this)
+{
+ if (this->notifies_response_list)
+ {
+ this->notifies_response_list->reset(this->notifies_response_list);
+ }
+}
+
+METHOD(peer_cfg_t, add_vendor_notifies, void,
+ private_peer_cfg_t *this, char *buffer)
+{
+ if (buffer)
+ {
+ int offset = 0;
+
+ vendor_request_data_t *request = build_vendor_request_data(buffer, &offset);
+ while (!request->is_empty(request))
+ {
+ this->notifies_request_list->insert_last(this->notifies_request_list, request);
+ request = build_vendor_request_data(buffer, &offset);
+ }
+ request->destroy(request);
+ }
+}
+
+METHOD(peer_cfg_t, put_vendor_notifies_to_message, void,
+ private_peer_cfg_t *this, message_t *message)
+{
+ vendor_request_data_t *notify;
+
+ /*
+ remove requested notifies
+ one time request only
+ */
+ while (this->notifies_request_list->remove_first(
+ this->notifies_request_list, ¬ify) == SUCCESS)
+ {
+ message->add_notify(message, FALSE,
+ notify->get_notify_type(notify), notify->get_data(notify));
+ notify->destroy(notify);
+ }
+}
#endif
METHOD(peer_cfg_t, destroy, void,
#endif /* ME */
#ifdef VOWIFI_CFG
DESTROY_IF(this->attributes_list);
+ DESTROY_IF(this->notifies_response_list);
+
+ vendor_request_data_t *req;
+ while (this->notifies_request_list->remove_first(
+ this->notifies_request_list, &req) == SUCCESS)
+ {
+ req->destroy(req);
+ }
+ DESTROY_IF(this->notifies_request_list);
#endif
DESTROY_IF(this->ppk_id);
this->lock->destroy(this->lock);
.get_next_vendor_attribute_request = _get_next_vendor_attribute_request,
.rewind_vendor_attributes_request_list = _rewind_vendor_attributes_request_list,
.set_dpd_interval = _set_dpd_interval,
+ .add_vendor_notifies = _add_vendor_notifies,
+ .put_vendor_notifies_to_message = _put_vendor_notifies_to_message,
+ .add_vendor_notifies_request_list = _add_vendor_notifies_request_list,
+ .is_vendor_notify_requested = _is_vendor_notify_requested,
+ .get_next_vendor_notify_request = _get_next_vendor_notify_request,
+ .rewind_vendor_notify_request_list = _rewind_vendor_notify_request_list,
#endif
#ifdef ME
.is_mediation = _is_mediation,
#endif /* ME */
#ifdef VOWIFI_CFG
.attributes_list = NULL,
+ .notifies_request_list = linked_list_create(),
+ .notifies_response_list = NULL,
#endif
);
return &this->public;
#include <config/ike_cfg.h>
#include <config/child_cfg.h>
#include <credentials/auth_cfg.h>
+#ifdef VOWIFI_CFG
+#include <encoding/message.h>
+#endif
/**
* Certificate sending policy. This is also used for certificate
int (*get_next_vendor_attribute_request)(peer_cfg_t *this);
void (*rewind_vendor_attributes_request_list)(peer_cfg_t *this);
+ /**
+ * Notifies list
+ */
+ void (*add_vendor_notifies)(peer_cfg_t *this, char* buffer);
+ void (*put_vendor_notifies_to_message)(peer_cfg_t *this, message_t *message);
+
+ /**
+ * Notifies vendor request list
+ */
+ void (*add_vendor_notifies_request_list)(peer_cfg_t *this, char *buffer);
+ bool (*is_vendor_notify_requested)(peer_cfg_t *this, int type);
+ int (*get_next_vendor_notify_request)(peer_cfg_t *this);
+ void (*rewind_vendor_notify_request_list)(peer_cfg_t *this);
+
/**
* Set DPD interval
*/
"ME_CONNECTAUTH",
"ME_RESPONSE",
"RADIUS_ATTRIBUTE");
-#ifndef VOWIFI_CFG
ENUM_END(notify_type_names, RADIUS_ATTRIBUTE);
-#else
-ENUM_NEXT(notify_type_names, BACKOFF_TIMER, BACKOFF_TIMER, RADIUS_ATTRIBUTE,
- "BACKOFF_TIMER");
-ENUM_END(notify_type_names, BACKOFF_TIMER);
-#endif
-
ENUM_BEGIN(notify_type_short_names, UNSUPPORTED_CRITICAL_PAYLOAD, UNSUPPORTED_CRITICAL_PAYLOAD,
"CRIT");
"ME_CAUTH",
"ME_R",
"RADIUS");
-#ifndef VOWIFI_CFG
ENUM_END(notify_type_short_names, RADIUS_ATTRIBUTE);
-#else
-ENUM_NEXT(notify_type_short_names, BACKOFF_TIMER, BACKOFF_TIMER, RADIUS_ATTRIBUTE,
- "BACKOFF_TMR");
-ENUM_END(notify_type_short_names, BACKOFF_TIMER);
-#endif
-
typedef struct private_notify_payload_t private_notify_payload_t;
bad_length = TRUE;
}
break;
-#ifdef VOWIFI_CFG
- case BACKOFF_TIMER:
- if (this->notify_data.len != 2)
- {
- bad_length = TRUE;
- }
- break;
-#endif
default:
/* TODO: verify */
break;
ME_RESPONSE = 40968,
/* RADIUS attribute received/to send to a AAA backend */
RADIUS_ATTRIBUTE = 40969,
-#ifdef VOWIFI_CFG
- /* 3GPP TS 24.302 */
- BACKOFF_TIMER = 41041,
-#endif
};
/**
peer_cfg->set_retransmit_base_handover(peer_cfg, msg->add_conn.retransmit_handover.base);
peer_cfg->set_retransmit_retries_handover(peer_cfg, msg->add_conn.retransmit_handover.tries);
peer_cfg->add_vendor_attributes_request_list(peer_cfg, msg->add_conn.response.attributes);
+ peer_cfg->add_vendor_notifies(peer_cfg, msg->add_conn.request.notifies);
+ peer_cfg->add_vendor_notifies_request_list(peer_cfg, msg->add_conn.response.notifies);
#endif
return peer_cfg;
}
/** MTU */
int mtu;
+
+ /** Vendor notifies */
+ linked_list_t *notifies;
#endif
#ifdef VOWIFI_USE_TIMER
int pmtu_sock;
#endif
-
-
/**
* Whether to follow IKEv2 redirects
*/
vip->destroy(vip);
}
+#ifdef VOWIFI_CFG
+ vendor_response_data_t *data;
+
+ while (this->notifies->remove_first(this->notifies, &data) == SUCCESS)
+ {
+ data->destroy(data);
+ }
+ DESTROY_IF(this->notifies);
+#endif
+
/* unset SA after here to avoid usage by the listeners */
charon->bus->set_sa(charon->bus, NULL);
this->peer_cfg->set_dpd_interval(this->peer_cfg, interval);
}
}
+
+METHOD(ike_sa_t, process_vendor_notify, void,
+ private_ike_sa_t *this, int type, message_t *message)
+{
+ if (this->peer_cfg)
+ {
+ if (this->peer_cfg->is_vendor_notify_requested(this->peer_cfg, type))
+ {
+ notify_payload_t* notify = message->get_notify(message, type);
+ if (notify)
+ {
+ vendor_response_data_t *data = build_vendor_response_data(type,
+ notify->get_notification_data(notify));
+ this->notifies->insert_last(this->notifies, data);
+ }
+ }
+ }
+}
+
+METHOD(ike_sa_t, process_failed_notify, void*,
+ private_ike_sa_t *this, int type, message_t *message)
+{
+ vendor_response_data_t *data;
+ linked_list_t *list = NULL;
+
+ if (this->peer_cfg)
+ {
+ int requested = this->peer_cfg->get_next_vendor_notify_request(this->peer_cfg);
+ while (requested)
+ {
+ notify_payload_t* notify = message->get_notify(message, requested);
+ if (notify)
+ {
+ data = build_vendor_response_data(requested,
+ notify->get_notification_data(notify));
+ if (list == NULL)
+ {
+ list = linked_list_create();
+ }
+ list->insert_last(list, data);
+ }
+ requested = this->peer_cfg->get_next_vendor_notify_request(this->peer_cfg);
+ }
+ this->peer_cfg->rewind_vendor_notify_request_list(this->peer_cfg);
+ }
+ if (list && list->get_count(list) > 0)
+ {
+ data = build_empty_response_data();
+ list->insert_last(list, data);
+ }
+ return list;
+}
+
+METHOD(ike_sa_t, get_vendor_notifies, int,
+ private_ike_sa_t *this, linked_list_t *list)
+{
+ vendor_response_data_t *response;
+ int total = 0;
+
+ charon->bus->set_sa(charon->bus, &this->public);
+
+ /* remove from internal list and send to service */
+ while (this->notifies->remove_first(this->notifies, &response) == SUCCESS)
+ {
+ total += response->get_length(response);
+ list->insert_last(list, response);
+ }
+
+ if (list->get_count(list) > 0)
+ {
+ vendor_response_data_t *response = build_empty_response_data();
+ total += response->get_length(response);
+ list->insert_last(list, response);
+ }
+ return total;
+}
#endif
#ifdef VOWIFI_USE_TIMER
.get_mtu = _get_mtu,
.get_configuration_attributes = _get_configuration_attributes,
.set_dpd_interval = _set_dpd_interval,
+ .process_vendor_notify = _process_vendor_notify,
+ .process_failed_notify = _process_failed_notify,
+ .get_vendor_notifies = _get_vendor_notifies,
#endif
#ifdef ME
.act_as_mediation_server = _act_as_mediation_server,
this->vip_thread_started = FALSE;
this->tun = NULL;
this->mtu = 0;
+ this->notifies = linked_list_create();
#endif
#ifdef VOWIFI_PMTU_DISCOVERY
this->pmtu_sock = -1;
* Set DPD interval
*/
void (*set_dpd_interval)(ike_sa_t *this, uint32_t interval);
+
+ /**
+ * Notifies control
+ */
+ void (*process_vendor_notify)(ike_sa_t *this, int type, message_t *message);
+ void* (*process_failed_notify)(ike_sa_t *this, int type, message_t *message);
+ int (*get_vendor_notifies)(ike_sa_t *this, linked_list_t *list);
#endif
};
return FAILED;
}
+#ifdef VOWIFI_CFG
+ peer_cfg->put_vendor_notifies_to_message(peer_cfg, message);
+#endif
+
this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy));
this->tsr->destroy_offset(this->tsr, offsetof(traffic_selector_t, destroy));
this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy));
{
if (type <= 16383)
{
-#ifdef VOWIFI_CFG
- int timer_val = 0;
- notify_payload_t* notify = message->get_notify(message, BACKOFF_TIMER);
- if (notify)
- {
- chunk_t data = notify->get_notification_data(notify);
- /* skip first bype, it is length */
- timer_val = data.ptr[1];
- }
-#endif
DBG1(DBG_IKE, "received %N notify error",
notify_type_names, type);
enumerator->destroy(enumerator);
charon->bus->alert(charon->bus, ALERT_LOCAL_AUTH_FAILED);
#ifdef VOWIFI_CFG
- charon->bus->alert(charon->bus, ALERT_NETWORK_FAILURE, type, timer_val);
+ void *data = this->ike_sa->process_failed_notify(this->ike_sa, type, message);
+ charon->bus->alert(charon->bus, ALERT_NETWORK_FAILURE, type, data);
#endif
return FAILED;
}
+#ifdef VOWIFI_CFG
+ this->ike_sa->process_vendor_notify(this->ike_sa, type, message);
+#endif
DBG2(DBG_IKE, "received %N notify",
notify_type_names, type);
break;