Switch to side-by-side view

--- a/src/DIF/Enrollment/Enrollment.cc
+++ b/src/DIF/Enrollment/Enrollment.cc
@@ -1,28 +1,765 @@
+// The MIT License (MIT)
 //
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-// 
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU Lesser General Public License for more details.
-// 
-// You should have received a copy of the GNU Lesser General Public License
-// along with this program.  If not, see http://www.gnu.org/licenses/.
-// 
+// Copyright (c) 2014-2016 Brno University of Technology, PRISTINE project
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+/**
+ * @file Enrollment.cc
+ * @author Kamil Jerabek (xjerab18@stud.fit.vutbr.cz)
+ * @date Apr 1, 2015
+ * @brief Enrollment and CACE
+ * @detail
+ */
+
 
 #include "Enrollment.h"
 
 Define_Module(Enrollment);
+
+const char* PAR_AUTH_TYPE       = "authType";
+const char* PAR_AUTH_NAME       = "authName";
+const char* PAR_AUTH_OTHER      = "authOther";
+const char* PAR_AUTH_PASS       = "authPassword";
+const char* PAR_CON_RETRIES     = "maxConRetries";
+const char* PAR_ISSELFENROL     = "isSelfEnrolled";
+
+const char* MSG_CONREQ                = "Connect/Auth";
+const char* MSG_CONREQRETRY           = "ConnectRetry/Auth";
+const char* MSG_CONRESPOS             = "Connect+/Auth";
+const char* MSG_CONRESNEG             = "Connect-/Auth";
+const char* MSG_ENRLCON               = "Enrol-Connect";
+const char* MSG_ENRLREL               = "Enrol-Release";
+
+const char* ELEM_PREENROL     = "Preenrollment";
+const char* ELEM_SIMTIME      = "SimTime";
+const char* ELEM_CONNECT      = "Connect";
+const char* ELEM_RELEASE      = "Release";
+const char* ATTR_TIME         = "t";
+
+Enrollment::Enrollment() :
+        StateTable(NULL), RibDaemon(NULL)
+{
+}
+
+Enrollment::~Enrollment(){
+    StateTable = NULL;
+    RibDaemon = NULL;
+}
 
 void Enrollment::initialize()
 {
-    // TODO - Generated method body
+    //Parse XML config
+    parseConfig(par(PAR_CONFIGDATA).xmlValue());
+
+    initSignalsAndListeners();
+    initPointers();
+
+    //Perform self-enrollment
+    bool isSelfEnrol = par(PAR_ISSELFENROL).boolValue();
+    if (isSelfEnrol) {
+        StateTable->insert(EnrollmentStateTableEntry(
+                APNamingInfo(FlowAlloc->getMyAddress().getApn()),
+                APNamingInfo(FlowAlloc->getMyAddress().getApn()),
+                EnrollmentStateTableEntry::CON_ESTABLISHED,
+                EnrollmentStateTableEntry::ENROLL_ENROLLED));
+        updateEnrollmentDisplay(ENICON_ENROLLED);
+    }
+    else {
+        //TODO: Work more on checking of N-1 flow existence
+        if (StateTable->isEnrolled(FlowAlloc->getMyAddress().getApn()))
+            { updateEnrollmentDisplay(ENICON_FLOWMIS); }
+        else
+            { updateEnrollmentDisplay(ENICON_NOTENROLLED); }
+    }
+
+    authType = par(PAR_AUTH_TYPE);
+    authName = this->par(PAR_AUTH_NAME).stringValue();
+    authPassword = this->par(PAR_AUTH_PASS).stringValue();
+    authOther = this->par(PAR_AUTH_OTHER).stringValue();
+
+    maxConRetries = this->par(PAR_CON_RETRIES);
+
+    WATCH_MAP(PreenrollConnects);
+    WATCH_MAP(PreenrollReleases);
+}
+
+void Enrollment::initPointers(){
+    StateTable = check_and_cast<EnrollmentStateTable*>(this->getParentModule()->getSubmodule(MOD_ENROLLMENTTABLE));
+    RibDaemon = check_and_cast<RIBd*>(this->getParentModule()->getParentModule()->getSubmodule(MOD_RIBDAEMON)->getSubmodule(MOD_RIBD));
+    FlowAlloc = check_and_cast<FABase*>( getModuleByPath("^.^.flowAllocator.fa") );
+}
+
+void Enrollment::initSignalsAndListeners() {
+    cModule* catcher1 = this->getParentModule()->getParentModule();
+
+    sigEnrollmentCACESendData   = registerSignal(SIG_ENROLLMENT_CACEDataSend);
+    sigEnrollmentSendData       = registerSignal(SIG_ENROLLMENT_DataSend);
+    sigEnrollmentStartEnrollReq = registerSignal(SIG_ENROLLMENT_StartEnrollmentRequest);
+    sigEnrollmentStartEnrollRes = registerSignal(SIG_ENROLLMENT_StartEnrollmentResponse);
+    sigEnrollmentStopEnrollReq  = registerSignal(SIG_ENROLLMENT_StopEnrollmentRequest);
+    sigEnrollmentStopEnrollRes  = registerSignal(SIG_ENROLLMENT_StopEnrollmentResponse);
+    sigEnrollmentStartOperReq   = registerSignal(SIG_ENROLLMENT_StartOperationRequest);
+    sigEnrollmentStartOperRes   = registerSignal(SIG_ENROLLMENT_StartOperationResponse);
+    sigEnrollmentFinish         = registerSignal(SIG_ENROLLMENT_Finished);
+
+    lisEnrollmentAllResPosi = new LisEnrollmentAllResPosi(this);
+    catcher1->subscribe(SIG_FA_MgmtFlowAllocated, lisEnrollmentAllResPosi);
+    catcher1->subscribe(SIG_RA_MgmtFlowAllocated, lisEnrollmentAllResPosi);
+
+    //lisEnrollmentGetFlowFromFaiCreResPosi = new LisEnrollmentGetFlowFromFaiCreResPosi(this);
+    //catcher1->subscribe(SIG_FAI_CreateFlowResponsePositive, lisEnrollmentGetFlowFromFaiCreResPosi);
+
+    lisEnrollmentStartEnrollReq = new LisEnrollmentStartEnrollReq(this);
+    catcher1->subscribe(SIG_RIBD_StartEnrollmentRequest, lisEnrollmentStartEnrollReq);
+
+    lisEnrollmentStartEnrollRes = new LisEnrollmentStartEnrollRes(this);
+    catcher1->subscribe(SIG_RIBD_StartEnrollmentResponse, lisEnrollmentStartEnrollRes);
+
+    lisEnrollmentStopEnrollReq = new LisEnrollmentStopEnrollReq(this);
+    catcher1->subscribe(SIG_RIBD_StopEnrollmentRequest, lisEnrollmentStopEnrollReq);
+
+    lisEnrollmentStopEnrollRes = new LisEnrollmentStopEnrollRes(this);
+    catcher1->subscribe(SIG_RIBD_StopEnrollmentResponse, lisEnrollmentStopEnrollRes);
+
+    lisEnrollmentStartOperationReq = new LisEnrollmentStopOperationReq(this);
+    catcher1->subscribe(SIG_RIBD_StartOperationRequest, lisEnrollmentStartOperationReq);
+
+    lisEnrollmentStartOperationRes = new LisEnrollmentStartOperationRes(this);
+    catcher1->subscribe(SIG_RIBD_StartOperationResponse, lisEnrollmentStartOperationRes);
+
+    lisEnrollmentConResPosi = new LisEnrollmentConResPosi(this);
+    catcher1->subscribe(SIG_RIBD_ConnectionResponsePositive, lisEnrollmentConResPosi);
+
+    lisEnrollmentConResNega = new LisEnrollmentConResNega(this);
+    catcher1->subscribe(SIG_RIBD_ConnectionResponseNegative, lisEnrollmentConResNega);
+
+    lisEnrollmentConReq = new LisEnrollmentConReq(this);
+    catcher1->subscribe(SIG_RIBD_ConnectionRequest, lisEnrollmentConReq);
+}
+
+void Enrollment::startCACE(APNIPair* apnip) {
+    Enter_Method("startCACE()");
+
+    auto entry = EnrollmentStateTableEntry(apnip->first, apnip->second, EnrollmentStateTableEntry::CON_AUTHENTICATING);
+    StateTable->insert(entry);
+
+    CDAP_M_Connect* msg = new CDAP_M_Connect(MSG_CONREQ);
+
+    authValue_t aValue;
+    aValue.authName = authName;
+    aValue.authPassword = authPassword;
+    aValue.authOther = authOther;
+
+    auth_t auth;
+    auth.authType = authType;
+    auth.authValue = aValue;
+
+    msg->setAuth(auth);
+    msg->setAbsSyntax(GPB);
+
+    APNamingInfo src = APNamingInfo(entry.getLocal().getApn(),
+                entry.getLocal().getApinstance(),
+                entry.getLocal().getAename(),
+                entry.getLocal().getAeinstance());
+
+    APNamingInfo dst = APNamingInfo(entry.getRemote().getApn(),
+            entry.getRemote().getApinstance(),
+            entry.getRemote().getAename(),
+            entry.getRemote().getAeinstance());
+    /*
+     * XXX: Vesely@Jerabek> Removing unnecessary *.msg ADT when there exists
+     *                      exactly the same ADT in RINASim source codes.
+    naming_t dst;
+    dst.AEInst = entry.getRemote().getAeinstance();
+    dst.AEName = entry.getRemote().getAename();
+    dst.ApInst = entry.getRemote().getApinstance();
+    dst.ApName = entry.getRemote().getApn().getName();
+
+    naming_t src;
+    src.AEInst = entry.getLocal().getAeinstance();
+    src.AEName = entry.getLocal().getAename();
+    src.ApInst = entry.getLocal().getApinstance();
+    src.ApName = entry.getLocal().getApn().getName();
+    */
+
+    msg->setSrc(src);
+    msg->setDst(dst);
+
+    msg->setSrcAddr(Address(entry.getLocal().getApn()));
+    msg->setDstAddr(Address(entry.getRemote().getApn()));
+
+    //send data to ribd to send
+    signalizeCACESendData(msg);
+}
+
+void Enrollment::insertStateTableEntry(Flow* flow){
+    //insert only first flow created (management flow)
+    if(StateTable->findEntryByDstAPN(APN(flow->getDstAddr().getApn().getName().c_str())) != NULL) {
+        return;
+    }
+    StateTable->insert(EnrollmentStateTableEntry(flow->getSrcApni(), flow->getDstApni(), EnrollmentStateTableEntry::CON_CONNECTPENDING));
+}
+
+void Enrollment::receivePositiveConnectResponse(CDAPMessage* msg) {
+    Enter_Method("receivePositiveConnectResponse()");
+
+    CDAP_M_Connect_R* cmsg = check_and_cast<CDAP_M_Connect_R*>(msg);
+    EnrollmentStateTableEntry* entry = StateTable->findEntryByDstAPN(cmsg->getSrc().getApn());
+
+    //check appropriate state
+    if (entry->getCACEConStatus() != EnrollmentStateTableEntry::CON_AUTHENTICATING) {
+        //TODO: send M_Release and invoke deallocate
+        return;
+    }
+
+    entry->setCACEConStatus(EnrollmentStateTableEntry::CON_ESTABLISHED);
+
+    startEnrollment(entry);
+}
+
+void Enrollment::receiveNegativeConnectResponse(CDAPMessage* msg) {
+    Enter_Method("receiveNegativeConnectResponse()");
+
+    CDAP_M_Connect_R* cmsg = check_and_cast<CDAP_M_Connect_R*>(msg);
+    EnrollmentStateTableEntry* entry = StateTable->findEntryByDstAPN(cmsg->getSrc().getApn());
+
+    //check appropriate state
+    if (entry->getCACEConStatus() != EnrollmentStateTableEntry::CON_AUTHENTICATING) {
+        //TODO: send M_Release and invoke deallocate
+        return;
+    }
+
+    if (this->maxConRetries <= entry->getCurrentConnectRetries()) {
+        entry->setCACEConStatus(EnrollmentStateTableEntry::CON_NIL);
+        //TODO: send release and deallocate
+        return;
+    }
+
+
+    entry->setCACEConStatus(EnrollmentStateTableEntry::CON_CONNECTPENDING);
+    entry->increaseCurrentConnectRetries();
+    //create and send new connect retry
+    processNewConReq(entry);
+}
+
+void Enrollment::receiveConnectRequest(CDAPMessage* msg) {
+    Enter_Method("receiveConnectRequest()");
+
+    CDAP_M_Connect* cmsg = check_and_cast<CDAP_M_Connect*>(msg);
+
+    auto ent = EnrollmentStateTableEntry(
+             cmsg->getDst(), cmsg->getSrc(), EnrollmentStateTableEntry::CON_CONNECTPENDING);
+    StateTable->insert(ent);
+
+    EnrollmentStateTableEntry* entry = StateTable->findEntryByDstAPN(cmsg->getSrc().getApn());
+
+    if (!entry) {
+        EV << "Enrollment status not found for "
+           << cmsg->getSrc().getApn() << endl;
+        return;
+    }
+
+    //check appropriate state
+    if (entry->getCACEConStatus() != EnrollmentStateTableEntry::CON_CONNECTPENDING) {
+        //TODO: send M_Release and invoke deallocate
+        return;
+    }
+
+    //check if message is valid
+    if (cmsg->getAbsSyntax() != GPB) {
+        this->processConResNega(entry, cmsg);
+        return;
+    }
+
+    entry->setCACEConStatus(EnrollmentStateTableEntry::CON_AUTHENTICATING);
+
+    authenticate(entry, cmsg);
+}
+
+/*   enrollment initiator */
+
+void Enrollment::startEnrollment(EnrollmentStateTableEntry* entry) {
+    Enter_Method("startEnrollment()");
+
+    auto enrollObj = new EnrollmentObj(Address(entry->getLocal().getApn()), Address(entry->getRemote().getApn()));
+
+    enrollObj->setAddress(APN(RibDaemon->getMyAddress().getIpcAddress().getName()));
+
+    //TODO: add other necessary information
+
+    //process enrollment object to ribd to send
+    signalizeStartEnrollmentRequest(enrollObj);
+
+    //set appropriate state
+    entry->setEnrollmentStatus(EnrollmentStateTableEntry::ENROLL_WAIT_START_RESPONSE_ENROLLMENT);
+}
+
+void Enrollment::receiveStartEnrollmentResponse(CDAPMessage* msg) {
+    Enter_Method("receiveStartEnrollmentResponse()");
+
+    CDAP_M_Start_R* smsg = check_and_cast<CDAP_M_Start_R*>(msg);
+
+    //not expected message
+    if (!smsg) {
+        //TODO: send release and deallocate
+        return;
+    }
+
+    EnrollmentObj* enrollRec = (check_and_cast<EnrollmentObj*>(smsg->getObject().objectVal))->dup();
+    EnrollmentStateTableEntry* entry = StateTable->findEntryByDstAPN(APN(enrollRec->getSrcAddress().getApn().getName().c_str()));
+
+    //check for appropriate state
+    if (entry->getEnrollmentStatus() != EnrollmentStateTableEntry::ENROLL_WAIT_START_RESPONSE_ENROLLMENT) {
+        //TODO: send release and deallocate
+        return;
+    }
+
+    //assign new, received address
+    Address newAddr = RibDaemon->getMyAddress();
+    newAddr.setIpcAddress(APN(enrollRec->getAddress().getName().c_str()));
+    RibDaemon->setMyAddress(newAddr);
+
+    //TODO: assign other received values
+
+    //change state
+    entry->setEnrollmentStatus(EnrollmentStateTableEntry::ENROLL_WAIT_STOP_ENROLLMENT);
+
+    //TODO: wait for create messages and stop enrollment request
+}
+
+void Enrollment::receiveStopEnrollmentRequest(CDAPMessage* msg) {
+    Enter_Method("receiveStopEnrollmentRequest()");
+
+
+    CDAP_M_Stop* smsg = check_and_cast<CDAP_M_Stop*>(msg);
+
+    //not expected message
+    if (!smsg) {
+        //TODO: send release and deallocate
+        return;
+    }
+
+    EnrollmentObj* enrollRec = (check_and_cast<EnrollmentObj*>(smsg->getObject().objectVal))->dup();
+    EnrollmentStateTableEntry* entry = StateTable->findEntryByDstAPN(APN(enrollRec->getSrcAddress().getApn().getName().c_str()));
+
+    //check for appropriate state
+    if (entry->getEnrollmentStatus() != EnrollmentStateTableEntry::ENROLL_WAIT_STOP_ENROLLMENT) {
+        //TODO: send release and deallocate
+        return;
+    }
+
+    //set immediate transition to operational state
+    entry->setIsImmediateEnrollment(enrollRec->getIsImmediate());
+
+    //set appropriate state
+    entry->setEnrollmentStatus(EnrollmentStateTableEntry::ENROLL_WAIT_READ_RESPONSE);
+
+    //TODO: send read requests, wait for responses, send Mstop enrollment
+    //for now send stop enrollment response
+    processStopEnrollmentResponse(entry);
+}
+
+void Enrollment::processStopEnrollmentResponse(EnrollmentStateTableEntry* entry) {
+
+    auto enrollObj = new EnrollmentObj(Address(entry->getLocal().getApn()), Address(entry->getRemote().getApn()));
+
+    signalizeStopEnrollmentResponse(enrollObj);
+
+    if (entry->getIsImmediateEnrollment()) {
+        entry->setEnrollmentStatus(EnrollmentStateTableEntry::ENROLL_ENROLLED);
+        signalizeEnrollmentFinished(entry);
+    }
+    else {
+        entry->setEnrollmentStatus(EnrollmentStateTableEntry::ENROLL_WAIT_START_OPERATION);
+        //TODO: continue enrollment here
+    }
+}
+
+void Enrollment::receiveStartOperationRequest(CDAPMessage* msg) {
+    Enter_Method("receiveStartOperationRequest()");
+
+}
+
+/* enrollment member */
+
+void Enrollment::receiveStartEnrollmentRequest(CDAPMessage* msg) {
+    Enter_Method("receiveStartEnrollmentRequest()");
+
+    CDAP_M_Start* smsg = check_and_cast<CDAP_M_Start*>(msg);
+
+    //not expected message
+    if (!smsg) {
+        //TODO: send release and deallocate
+        return;
+    }
+
+    EnrollmentObj* enrollRec = (check_and_cast<EnrollmentObj*>(smsg->getObject().objectVal))->dup();
+    EnrollmentStateTableEntry* entry = StateTable->findEntryByDstAPN(APN(enrollRec->getSrcAddress().getApn().getName().c_str()));
+
+    //check for appropriate state
+    if (entry->getEnrollmentStatus() != EnrollmentStateTableEntry::ENROLL_WAIT_START_ENROLLMENT) {
+        //TODO: send release and deallocate
+        return;
+    }
+
+
+    auto enrollObj = new EnrollmentObj(Address(entry->getLocal().getApn()), Address(entry->getRemote().getApn()));
+
+    //TODO: repair this dummy address assign
+    enrollObj->setAddress(APN(enrollRec->getAddress().getName()));
+
+    //TODO: add other necessary information
+
+    //process enrollment object to ribd to send
+    signalizeStartEnrollmentResponse(enrollObj);
+
+    //TODO: send create messages, wait for responses, then send stop enrollment
+    //for now send stop enrollment
+    processStopEnrollmentImmediate(entry);
+}
+
+void Enrollment::receiveStopEnrollmentResponse(CDAPMessage* msg) {
+    Enter_Method("receiveStopEnrollmentResponse()");
+
+    CDAP_M_Stop_R* smsg = check_and_cast<CDAP_M_Stop_R*>(msg);
+
+    //not expected message
+    if (!smsg) {
+        //TODO: send release and deallocate
+        return;
+    }
+
+    EnrollmentObj* enrollRec = (check_and_cast<EnrollmentObj*>(smsg->getObject().objectVal))->dup();
+    EnrollmentStateTableEntry* entry = StateTable->findEntryByDstAPN(APN(enrollRec->getSrcAddress().getApn().getName().c_str()));
+
+    //check for appropriate state
+    if (entry->getEnrollmentStatus() != EnrollmentStateTableEntry::ENROLL_WAIT_STOP_RESPONSE_ENROLLMENT) {
+        //TODO: send release and deallocate
+        return;
+    }
+
+    if (entry->getIsImmediateEnrollment()) {
+        entry->setEnrollmentStatus(EnrollmentStateTableEntry::ENROLL_ENROLLED);
+        //TODO: emit signal somewhere and probably send rib update ...
+    }
+    else {
+        //TODO: add appropriate state for read and wait operation
+    }
+}
+
+void Enrollment::receiveStartOperationResponse(CDAPMessage* msg) {
+    Enter_Method("receiveStartOperationResponse()");
+
+}
+
+void Enrollment::processStopEnrollmentImmediate(EnrollmentStateTableEntry* entry) {
+    auto enrollObj = new EnrollmentObj(Address(entry->getLocal().getApn()), Address(entry->getRemote().getApn()));
+
+    //set immediate
+    enrollObj->setIsImmediate(true);
+    entry->setIsImmediateEnrollment(true);
+
+    //TODO: add other necessary information
+
+    signalizeStopEnrollmentRequest(enrollObj);
+
+    entry->setEnrollmentStatus(EnrollmentStateTableEntry::ENROLL_WAIT_STOP_RESPONSE_ENROLLMENT);
+}
+
+void Enrollment::authenticate(EnrollmentStateTableEntry* entry, CDAP_M_Connect* msg) {
+    Enter_Method("authenticate()");
+
+    //check and validate expected auth type
+    if (msg->getAuth().authType == authType) {
+        //none auth option
+        if (msg->getAuth().authType == AUTH_NONE) {
+            processConResPosi(entry, msg);
+            return;
+
+        }
+        //passwd auth option
+        else if (msg->getAuth().authType == AUTH_PASSWD) {
+            //correct passwd
+            if (!strcmp(msg->getAuth().authValue.authPassword.c_str(), authPassword.c_str())) {
+                processConResPosi(entry, msg);
+                return;
+            }
+        }
+        //TODO: support for other options
+    }
+
+    //not valid auth send negative response
+    processConResNega(entry, msg);
+}
+
+void Enrollment::processNewConReq(EnrollmentStateTableEntry* entry) {
+    Enter_Method("processNewConReq()");
+
+    //TODO: probably change values, this is retry
+
+    CDAP_M_Connect* msg = new CDAP_M_Connect(MSG_CONREQRETRY);
+
+    authValue_t aValue;
+    aValue.authName = authName;
+    aValue.authPassword = authPassword;
+    aValue.authOther = authOther;
+
+    auth_t auth;
+    auth.authType = authType;
+    auth.authValue = aValue;
+
+    msg->setAuth(auth);
+    msg->setAbsSyntax(GPB);
+
+    APNamingInfo src = APNamingInfo(entry->getLocal().getApn(),
+                entry->getLocal().getApinstance(),
+                entry->getLocal().getAename(),
+                entry->getLocal().getAeinstance());
+
+    APNamingInfo dst = APNamingInfo(entry->getRemote().getApn(),
+            entry->getRemote().getApinstance(),
+            entry->getRemote().getAename(),
+            entry->getRemote().getAeinstance());
+
+    msg->setSrc(src);
+    msg->setDst(dst);
+
+    msg->setSrcAddr(Address(entry->getLocal().getApn()));
+    msg->setDstAddr(Address(entry->getRemote().getApn()));
+
+    //send data to ribd to send
+    signalizeCACESendData(msg);
+
+    //change state to auth after send retry
+    entry->setCACEConStatus(EnrollmentStateTableEntry::CON_AUTHENTICATING);
+}
+
+void Enrollment::processConResPosi(EnrollmentStateTableEntry* entry, CDAPMessage* cmsg) {
+    CDAP_M_Connect_R* msg = new CDAP_M_Connect_R(MSG_CONRESPOS);
+    CDAP_M_Connect* cmsg1 = check_and_cast<CDAP_M_Connect*>(cmsg);
+
+    APNamingInfo src = APNamingInfo(entry->getLocal().getApn(),
+                entry->getLocal().getApinstance(),
+                entry->getLocal().getAename(),
+                entry->getLocal().getAeinstance());
+
+    APNamingInfo dst = APNamingInfo(entry->getRemote().getApn(),
+            entry->getRemote().getApinstance(),
+            entry->getRemote().getAename(),
+            entry->getRemote().getAeinstance());
+
+    result_t result;
+    result.resultValue = R_SUCCESS;
+
+    auth_t auth;
+    auth.authType = cmsg1->getAuth().authType;
+    auth.authValue = cmsg1->getAuth().authValue;
+
+    msg->setAbsSyntax(GPB);
+    msg->setResult(result);
+    msg->setAuth(auth);
+
+    msg->setSrc(src);
+    msg->setDst(dst);
+
+    msg->setSrcAddr(Address(entry->getLocal().getApn()));
+    msg->setDstAddr(Address(entry->getRemote().getApn()));
+
+    //send data to ribd to send
+    signalizeCACESendData(msg);
+
+    entry->setCACEConStatus(EnrollmentStateTableEntry::CON_ESTABLISHED);
+    entry->setEnrollmentStatus(EnrollmentStateTableEntry::ENROLL_WAIT_START_ENROLLMENT);
+}
+
+void Enrollment::processConResNega(EnrollmentStateTableEntry* entry, CDAPMessage* cmsg) {
+    CDAP_M_Connect_R* msg = new CDAP_M_Connect_R(MSG_CONRESNEG);
+    CDAP_M_Connect* cmsg1 = check_and_cast<CDAP_M_Connect*>(cmsg);
+
+    APNamingInfo src = APNamingInfo(entry->getLocal().getApn(),
+                entry->getLocal().getApinstance(),
+                entry->getLocal().getAename(),
+                entry->getLocal().getAeinstance());
+
+    APNamingInfo dst = APNamingInfo(entry->getRemote().getApn(),
+            entry->getRemote().getApinstance(),
+            entry->getRemote().getAename(),
+            entry->getRemote().getAeinstance());
+
+    result_t result;
+    result.resultValue = R_FAIL;
+
+    auth_t auth;
+    auth.authType = cmsg1->getAuth().authType;
+    auth.authValue = cmsg1->getAuth().authValue;
+
+    msg->setAbsSyntax(GPB);
+    msg->setResult(result);
+    msg->setAuth(auth);
+
+    msg->setSrc(src);
+    msg->setDst(dst);
+
+    msg->setSrcAddr(Address(entry->getLocal().getApn()));
+    msg->setDstAddr(Address(entry->getRemote().getApn()));
+
+    //send data to send to ribd
+    signalizeCACESendData(msg);
+
+    entry->setCACEConStatus(EnrollmentStateTableEntry::CON_CONNECTPENDING);
+
+    //increase number of connects
+    entry->increaseCurrentConnectRetries();
+}
+
+void Enrollment::signalizeCACESendData(CDAPMessage* cmsg) {
+    emit(sigEnrollmentCACESendData, cmsg);
+}
+
+void Enrollment::signalizeStartEnrollmentRequest(EnrollmentObj* obj) {
+    emit(sigEnrollmentStartEnrollReq, obj);
+}
+
+void Enrollment::signalizeStartEnrollmentResponse(EnrollmentObj* obj) {
+    emit(sigEnrollmentStartEnrollRes, obj);
+}
+
+void Enrollment::signalizeStopEnrollmentRequest(EnrollmentObj* obj) {
+    emit(sigEnrollmentStopEnrollReq, obj);
+}
+
+void Enrollment::signalizeStopEnrollmentResponse(EnrollmentObj* obj) {
+    emit(sigEnrollmentStopEnrollRes, obj);
+}
+
+void Enrollment::signalizeStartOperationRequest(OperationObj* obj) {
+    emit(sigEnrollmentStartOperReq, obj);
+}
+
+void Enrollment::signalizeStartOperationResponse(OperationObj* obj) {
+    emit(sigEnrollmentStartOperRes, obj);
+}
+
+void Enrollment::signalizeEnrollmentFinished(EnrollmentStateTableEntry* entry) {
+    updateEnrollmentDisplay(ENICON_ENROLLED);
+    APNIPair* apnip = new APNIPair(entry->getLocal(), entry->getRemote());
+    emit(sigEnrollmentFinish, apnip);
+}
+
+void Enrollment::parseConfig(cXMLElement* config) {
+    cXMLElement* mainTag = NULL;
+    if (config != NULL && config->hasChildren() && config->getFirstChildWithTag(ELEM_PREENROL))
+        mainTag = config->getFirstChildWithTag(ELEM_PREENROL);
+    else {
+        EV << "configData parameter not initialized!" << endl;
+        return;
+    }
+
+    cXMLElementList enrll = mainTag->getChildrenByTagName(ELEM_SIMTIME);
+    for (cXMLElementList::const_iterator it = enrll.begin(); it != enrll.end(); ++it) {
+        cXMLElement* m = *it;
+
+        if (!m->getAttribute(ATTR_TIME)) {
+            EV << "\nSimTime tag is missing time attribute!" << endl;
+            continue;
+        }
+
+        simtime_t cas = atof(m->getAttribute(ATTR_TIME));
+
+        if (m->getFirstChildWithTag(ELEM_CONNECT)) {
+            PreenrollConnects[cas] = new APNIPairs();
+            cMessage* cmsg = new cMessage(MSG_ENRLCON);
+            scheduleAt(cas, cmsg);
+        }
+
+        if (m->getFirstChildWithTag(ELEM_RELEASE)) {
+            PreenrollReleases[cas] = new APNIPairs();
+            cMessage* cmsg = new cMessage(MSG_ENRLREL);
+            scheduleAt(cas, cmsg);
+        }
+
+        cXMLElementList coms = m->getChildren();
+        for (cXMLElementList::const_iterator jt = coms.begin(); jt != coms.end(); ++jt) {
+            cXMLElement* n = *jt;
+
+            if ( !( strcmp(n->getTagName(), ELEM_CONNECT) xor strcmp(n->getTagName(), ELEM_RELEASE) )
+                    && !(n->getAttribute(ATTR_SRC))
+                    && !(n->getAttribute(ATTR_DST))
+               ) {
+                EV << "\nError when parsing Connect/Release record" << endl;
+                continue;
+            }
+
+            if ( !strcmp(n->getTagName(), ELEM_CONNECT) ) {
+                PreenrollConnects[cas]->push_back( APNIPair(n->getAttribute(ATTR_SRC), n->getAttribute(ATTR_DST)) );
+                //EV << "!!!!!!!!!!!!!" << PreenrollConnects[cas]->size() << endl;
+            }
+            else if ( !strcmp(n->getTagName(), ELEM_RELEASE) ) {
+                PreenrollReleases[cas]->push_back( APNIPair(n->getAttribute(ATTR_SRC), n->getAttribute(ATTR_DST)) );
+            }
+        }
+    }
+}
+
+void Enrollment::updateEnrollmentDisplay(Enrollment::IconEnrolStatus status) {
+    cModule* ipc = this->getParentModule()->getParentModule();
+    std::string ico, col;
+    switch (status) {
+        case ENICON_ENROLLED: {ico="status/check"; col="green"; break;}
+        case ENICON_FLOWMIS: {ico="status/excl"; col="yellow";break;}
+        case ENICON_NOTENROLLED:
+        default:              {ico="status/cross"; col="red"; break;}
+
+    }
+    ipc->getDisplayString().setTagArg("i2", 0, ico.c_str());
+    ipc->getDisplayString().setTagArg("i2", 1, col.c_str());
 }
 
 void Enrollment::handleMessage(cMessage *msg)
 {
-    // TODO - Generated method body
-}
+    if (msg->isSelfMessage()) {
+        if ( !opp_strcmp(msg->getName(), MSG_ENRLCON) ) {
+            APNIPairs* apnip = PreenrollConnects[simTime()];
+
+            while (!apnip->empty())
+            {
+                APNIPair pair = apnip->front();
+                auto entry = StateTable->findEntryByDstAPN(pair.second.getApn());
+                if (!entry) {
+                    FlowAlloc->receiveMgmtAllocateRequest(pair.first, pair.second);
+                }
+                apnip->pop_front();
+            }
+        }
+        else if ( !opp_strcmp(msg->getName(), MSG_ENRLREL) ) {
+            APNIPairs* apnip = PreenrollReleases[simTime()];
+            while (!apnip->empty())
+            {
+                APNIPair pair = apnip->front();
+                auto entry = StateTable->findEntryByDstAPN(pair.second.getApn());
+                if (entry && entry->getEnrollmentStatus() == EnrollmentStateTableEntry::ENROLL_ENROLLED ) {
+                    //FIXME: Vesely->Jerabek: Here goes release part of Enrollment
+                }
+                apnip->pop_front();
+            }
+        }
+        delete msg;
+    }
+}