[APR-5172]add vendor specific notifies processing
authorDenis Vinogradov <denis.vinogradov@samsung.com>
Thu, 3 Sep 2020 08:49:49 +0000 (17:49 +0900)
committerrobot <robot@samsung.com>
Fri, 18 Sep 2020 03:12:29 +0000 (12:12 +0900)
[Issue] SOC-101097
[Problem/Cause] vendor specific notifies not supported.
[Solution] support to add vendor specific notifies processing.

Change-Id: I9a2eff352dd9ce6c15d5db4310221ab605f9516d
Signed-off-by: Denis Vinogradov <denis.vinogradov@samsung.com>
18 files changed:
src/libcharon/comm/alerts.c
src/libcharon/comm/alerts.h
src/libcharon/comm/comm_msg.c
src/libcharon/comm/comm_msg.h
src/libcharon/comm/vendor_request_data.c
src/libcharon/comm/vendor_request_data.h
src/libcharon/comm/vendor_request_list.c
src/libcharon/comm/vendor_request_list.h
src/libcharon/comm/vendor_response_data.c
src/libcharon/config/peer_cfg.c
src/libcharon/config/peer_cfg.h
src/libcharon/encoding/payloads/notify_payload.c
src/libcharon/encoding/payloads/notify_payload.h
src/libcharon/plugins/stroke/stroke_config.c
src/libcharon/sa/ike_sa.c
src/libcharon/sa/ike_sa.h
src/libcharon/sa/ikev2/tasks/child_create.c
src/libcharon/sa/ikev2/tasks/ike_auth.c

index e59ebc541d1ae5c73d9fe2c6f590d47706cec219..057ec94680a6b6027ba28071dd986dfe01f05102 100755 (executable)
@@ -9,11 +9,11 @@
 #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];
@@ -31,15 +31,15 @@ int get_alerts_notify(int index)
        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)
@@ -65,7 +65,7 @@ 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;
                }
@@ -105,8 +105,8 @@ void set_alert(ike_sa_t *ike_sa, alert_t alert, va_list args)
                        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;
index 22149900a99e905a0de4b9cfec88f08fb9a80046..da7e037bfcf503c7e7a11ea23bc0eba18f106115 100755 (executable)
@@ -4,7 +4,7 @@
 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);
 
index 38e924f6f3a3b6cf67be6586043212f69df11cee..f620c0cc988a89a202a570fcb133e7461c13a072 100755 (executable)
@@ -133,24 +133,81 @@ void charon_send_initate_failure(stroke_msg_t *msg, int index)
 {
        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, &notify) == 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();
@@ -251,26 +308,34 @@ void charon_send_initiate_success(stroke_msg_t *msg, int index)
        {
                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 */
index 1f75b4d9d98d005789b440cbd821e23ecae00cd2..deea8ab3e03bd42d1971b02b37f4fe9d34a2e30d 100755 (executable)
@@ -81,7 +81,6 @@ typedef struct
                        char *name;
                        charon_error_code_t status;
                        int notify;
-                       int tmval;
                        char *device;
                        char *address;
                        char *attributes;
index 217a8b0204aa925046e735a875e6f78937a02c99..d6669c0b9d18933d2fbaebc39280ec7497dde8ba 100755 (executable)
@@ -33,6 +33,12 @@ METHOD(vendor_request_data_t, get_attribute_type, configuration_attribute_type_t
        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)
 {
@@ -62,6 +68,7 @@ vendor_request_data_t* build_vendor_request_data(char *buffer, int *offset)
        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,
@@ -88,6 +95,7 @@ vendor_request_data_t* build_dns_request_data(host_t* host)
        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,
@@ -105,7 +113,8 @@ vendor_request_data_t* build_dns_request_data(host_t* host)
        }
        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;
index 98fb39d3ab83f2745c601cc1b97ae86a8c93feb3..6ea0b5a9fca54a96c150e6d10bf3bdadc56148e3 100755 (executable)
@@ -9,6 +9,9 @@ struct vendor_request_data_t {
        /* 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);
 
index 0d4c913043f087c234c5ebf0adffde3ad7fcacc4..8eaf2015a50b8c48b8a99881c23efb16d42c7d82 100755 (executable)
@@ -21,6 +21,22 @@ struct private_vendor_request_list_t {
        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)
 {
@@ -53,6 +69,7 @@ vendor_request_list_t* build_vendor_request_list(char *buffer)
 
        INIT(this,
                .public = {
+                       .is_requested = _is_requested,
                        .get_next = _get_next,
                        .reset = _reset,
                        .destroy = _destroy,
index f4c5c27dd991b12c25964548e8733d31145e0371..04ae5b4de24330ae31978da973348e4291a2b67c 100755 (executable)
@@ -6,6 +6,9 @@
 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);
 
index 00b05aa64a241897d90f5bef6e932d23a8356a2c..1c8510fce876efa259e80fab551be82c29c9a3e9 100755 (executable)
@@ -49,6 +49,10 @@ METHOD(vendor_response_data_t, pack, char*,
 METHOD(vendor_response_data_t, destroy, void,
        private_vendor_response_data_t *this)
 {
+       if (this->data.ptr)
+       {
+               chunk_free(&this->data);
+       }
        free(this);
 }
 
@@ -63,7 +67,7 @@ vendor_response_data_t* build_vendor_response_data(int type, chunk_t data)
                        .destroy = _destroy,
                },
                .type = type,
-               .data = data,
+               .data = chunk_clone(data),
        );
        return &this->public;
 }
index 155cc129c46c08bcc8c25d2dd31762d96c27950c..69797a78a7a7b27e667e6be59ca65222627b888b 100755 (executable)
@@ -26,6 +26,7 @@
 #include <utils/identification.h>
 
 #ifdef VOWIFI_CFG
+#include "vendor_request_data.h"
 #include "vendor_request_list.h"
 #endif
 
@@ -231,6 +232,20 @@ struct private_peer_cfg_t {
        * 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
 };
 
@@ -958,6 +973,79 @@ METHOD(peer_cfg_t, set_dpd_interval, void,
 {
        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, &notify) == 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,
@@ -980,6 +1068,15 @@ 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);
@@ -1069,6 +1166,12 @@ peer_cfg_t *peer_cfg_create(char *name, ike_cfg_t *ike_cfg,
                        .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,
@@ -1108,6 +1211,8 @@ peer_cfg_t *peer_cfg_create(char *name, ike_cfg_t *ike_cfg,
 #endif /* ME */
 #ifdef VOWIFI_CFG
                .attributes_list = NULL,
+               .notifies_request_list = linked_list_create(),
+               .notifies_response_list = NULL,
 #endif
        );
        return &this->public;
index 1cfb1d00c615d014ea71b093ecb764b0778bdd15..cbc8fda29d6351d0a9c9fc8b1e33f5b8a942d17e 100755 (executable)
@@ -36,6 +36,9 @@ typedef struct peer_cfg_create_t peer_cfg_create_t;
 #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
@@ -464,6 +467,20 @@ struct peer_cfg_t {
        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
        */
index dec0b12ed8ce2151cc6d2516b0147f098b49168e..a4bbb899b04e660d52b27224b57b757e77a7a464 100755 (executable)
@@ -136,14 +136,7 @@ ENUM_NEXT(notify_type_names, ME_MEDIATION, RADIUS_ATTRIBUTE, USE_BEET_MODE,
        "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");
@@ -256,14 +249,7 @@ ENUM_NEXT(notify_type_short_names, ME_MEDIATION, RADIUS_ATTRIBUTE, USE_BEET_MODE
        "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;
 
@@ -569,14 +555,6 @@ METHOD(payload_t, verify, status_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;
index fdcf0a90a9cb26a61a3467df63cf0567794d0132..b0cf69d02e349ae63eb93222320b1de495c5541c 100755 (executable)
@@ -178,10 +178,6 @@ enum notify_type_t {
        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
 };
 
 /**
index 372d83801995436fb27659054a2770d1ec40fa77..9c21773a6c1aa62ad1e7556a650f9c014b7b06ed 100755 (executable)
@@ -904,6 +904,8 @@ static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this,
        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;
 }
index 8fe598b37dd35019453df66abc8adcbb16f803d2..9b19a8ded135f6f267a792a93088bd27f299a273 100755 (executable)
@@ -304,6 +304,9 @@ struct private_ike_sa_t {
 
        /** MTU */
        int mtu;
+
+       /** Vendor notifies */
+       linked_list_t *notifies;
 #endif
 
 #ifdef VOWIFI_USE_TIMER
@@ -318,8 +321,6 @@ struct private_ike_sa_t {
        int pmtu_sock;
 #endif
 
-
-
        /**
         * Whether to follow IKEv2 redirects
         */
@@ -3568,6 +3569,16 @@ METHOD(ike_sa_t, destroy, void,
                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);
 
@@ -3741,6 +3752,82 @@ METHOD(ike_sa_t, set_dpd_interval, void,
                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
@@ -3890,6 +3977,9 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator,
                        .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,
@@ -3944,6 +4034,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator,
        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;
index 7a1ee761fb5e0ade456f5781d0bbc4d9552a2f9b..fbaa639e21d9e6359e40a1806f15ff5448ab0703 100755 (executable)
@@ -1259,6 +1259,13 @@ struct ike_sa_t {
        * 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
 };
 
index 299e98ba9383315510e95b0c77b560c4c03c1ee4..9adf4dac404f870c93560fd0e42bcd0eaf7337e3 100755 (executable)
@@ -1233,6 +1233,10 @@ METHOD(task_t, build_i, status_t,
                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));
index 1edbc463cdf89c23f48b220c3f00aeeef4d3ee6a..72a81dc39fe4c289f5a0beb01fac30c795324ce7 100755 (executable)
@@ -1275,25 +1275,19 @@ METHOD(task_t, process_i, status_t,
                                {
                                        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;