提交 3ca42384 编写于 作者: C calincerchez

begin nas

上级 afd882c3
//
// Copyright (C) 2012 Calin Cerchez
//
// 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/.
//
#include "EMMEntity.h"
#include "NAS.h"
#include "NASSerializer.h"
#include "LTEUtils.h"
#include "NASUtils.h"
#include "PhyControlInfo_m.h"
EMMEntity::EMMEntity() {
init();
}
EMMEntity::EMMEntity(unsigned char appType) {
// TODO Auto-generated constructor stub
init();
this->appType = appType;
nasKey = uniform(0, 6);
if (appType == UE_APPL_TYPE) {
fsm = new cFSM("fsm-EMM-UE");
fsm->setState(EMM_NULL);
take(fsm);
} else if (appType == MME_APPL_TYPE) {
fsm = new cFSM("fsm-EMM-MME");
fsm->setState(EMM_DEREGISTERED_N);
take(fsm);
}
}
EMMEntity::~EMMEntity() {
// TODO Auto-generated destructor stub
if (fsm != NULL)
dropAndDelete(fsm);
if (imsi != NULL)
delete imsi;
delete [] ueNetworkCapability;
if (t3410 != NULL) {
if (t3410->getContextPointer() != NULL)
module->cancelEvent(t3410);
delete t3410;
}
if (t3402 != NULL) {
if (t3402->getContextPointer() != NULL)
module->cancelEvent(t3402);
delete t3402;
}
if (t3411 != NULL) {
if (t3411->getContextPointer() != NULL)
module->cancelEvent(t3411);
delete t3411;
}
if (t3450 != NULL) {
if (t3450->getContextPointer() != NULL)
module->cancelEvent(t3450);
delete t3450;
}
}
void EMMEntity::init() {
attCounter = 0;
tracAreaUpdCounter = 0;
nasKey = 0;
appType = 0;
module = NULL;
epsUpdSt = -1;
fsm = NULL;
ueNetworkCapability = new char[3];
ueNetworkCapability[0] = 0x02;
ueNetworkCapability[1] = 0x80;
ueNetworkCapability[2] = 0x40;
emmCause = -1;
t3402 = NULL;
t3410 = NULL;
t3411 = NULL;
t3450 = NULL;
imsi = NULL;
tmsi = 0;
peer = NULL;
}
void EMMEntity::performStateTransition(EMMSublayerEvent event) {
int oldState = fsm->getState();
switch(oldState) {
case EMM_NULL:
switch(event) {
case SwitchOn: // switch on
FSM_Goto(*fsm, EMM_DEREGISTERED_PLMN_SEARCH);
break;
default:
EV << "NAS-EMM: Received unexpected event\n";
break;
}
break;
case EMM_DEREGISTERED_PLMN_SEARCH:
switch(event) {
case NoUSIM:
FSM_Goto(*fsm, EMM_DEREGISTERED_NO_IMSI);
break;
case CellFoundPermittedPLMN:
FSM_Goto(*fsm, EMM_DEREGISTERED_NORMAL_SERVICE);
break;
default:
EV << "NAS-EMM: Received unexpected event\n";
break;
}
break;
case EMM_DEREGISTERED_NORMAL_SERVICE:
switch(event) {
case AttachRequested:
FSM_Goto(*fsm, EMM_REGISTERED_INITIATED);
break;
default:
EV << "NAS-EMM: Received unexpected event\n";
break;
}
break;
case EMM_DEREGISTERED_N:
switch(event) {
case AttachAccepted: {
if (tmsi == 0) {
tmsi = uniform(1, 1000);
FSM_Goto(*fsm, EMM_COMMON_PROCEDURE_INITIATED);
}
NASPlainMessage *msg = createAttachAccept();
module->sendToS1AP(msg, ownerp->getEnbId(), ownerp->getMmeId());
// else remain in this state
break;
}
case AttachRejected: {
NASPlainMessage *msg = createAttachReject();
module->sendToS1AP(msg, ownerp->getEnbId(), ownerp->getMmeId());
break;
}
case AttachCompleted: {
/* TODO stop T3450 */
FSM_Goto(*fsm, EMM_REGISTERED_N);
break;
}
default:
EV << "NAS-EMM: Received unexpected event\n";
break;
}
break;
case EMM_REGISTERED_INITIATED:
switch(event) {
case AttachAccepted: {
attCounter = 0;
tracAreaUpdCounter = 0;
module->cancelEvent(t3410);
epsUpdSt = EU1_UPDATED;
NASPlainMessage *msg = createAttachComplete();
module->sendToRadio(msg, module->getChannelNumber());
FSM_Goto(*fsm, EMM_REGISTERED_U);
break;
}
case AttachRejected: {
if (emmCause == EPSServNonEPSServNotAllowed) {
epsUpdSt = EU3_ROAMING_NOT_ALLOWED;
FSM_Goto(*fsm, EMM_DEREGISTERED_U);
}
break;
}
default:
EV << "NAS-EMM: Received unexpected event\n";
break;
}
break;
case EMM_COMMON_PROCEDURE_INITIATED:
switch(event) {
case AttachCompleted:
/* TODO stop T3450 */
FSM_Goto(*fsm, EMM_REGISTERED_N);
break;
default:
EV << "NAS-EMM: Received unexpected event\n";
break;
}
break;
default:
EV << "NAS-EMM: Unknown state\n";
break;
}
if (oldState != fsm->getState())
EV << "NAS-EMM: PSM-Transition: " << stateName(oldState) << " --> " << stateName(fsm->getState()) << " (event was: " << eventName(event) << ")\n";
else
EV << "NAS-EMM: Staying in state: " << stateName(fsm->getState()) << " (event was: " << eventName(event) << ")\n";
stateEntered();
}
void EMMEntity::stateEntered() {
switch(fsm->getState()) {
case EMM_DEREGISTERED_NORMAL_SERVICE: {
attCounter = 0;
// send attach request with default pdn connection
NASPlainMessage *msg = createAttachRequest();
module->sendToRadio(msg, module->getChannelNumber());
// start t3410, reset t3402 and t3411
startT3410();
// go to EMM_REGISTERED_INITIATED
ownerp->setStatus(SUB_PENDING);
performStateTransition(AttachRequested);
break;
}
case EMM_DEREGISTERED_U:
case EMM_DEREGISTERED_N:
ownerp->setStatus(SUB_INACTIVE);
break;
case EMM_REGISTERED_NORMAL_SERVICE:
case EMM_REGISTERED_N:
ownerp->setStatus(SUB_ACTIVE);
break;
default:
break;
}
}
NASPlainMessage *EMMEntity::createAttachRequest() {
NASPlainMessage *msg = new NASPlainMessage("Attach-Request");
msg->setHdr(NASUtils().createHeader(0, PlainNASMessage, EMMMessage, 0, AttachRequest));
msg->setIesArraySize(5);
/* NAS key set identifier */
msg->setIes(0, NASUtils().createIE(IE_V, IEType1, 0, nasKey));
/* EPS attach type */
msg->setIes(1, NASUtils().createIE(IE_V, IEType1, 0, EPSAttach));
/* EPS mobile identity */
msg->setIes(2, NASUtils().createEPSMobileIdIE(IE_LV, IMSI_ID, imsi));
/* UE network capability */
msg->setIes(3, NASUtils().createIE(IE_LV, IEType4, 0, 3, ueNetworkCapability));
/* ESM message container */
NASPlainMessage *pdnConnReq = peer->getDefPDNConnection()->createPDNConnectivityRequest();
msg->encapsulate(pdnConnReq);
msg->setEncapPos(4);
return msg;
}
void EMMEntity::processAttachRequest(NASPlainMessage *msg) {
/* EPS mobile identity */
char *id;
unsigned len = NASUtils().processEPSMobileIdIE(msg->getIes(2), id);
if (len == IMSI_CODED_SIZE)
imsi = id;
/* ESM message container */
NASPlainMessage *smsg = check_and_cast<NASPlainMessage*>(msg->decapsulate());
if (smsg->getHdr().getMsgType() == PDNConnectivityRequest) {
// initialize PDN connection for this UE
PDNConnection *conn = new PDNConnection(peer);
conn->processPDNConnectivityRequest(smsg);
if (fsm->getState() == EMM_DEREGISTERED_N)
peer->addPDNConnection(conn, true);
else
peer->addPDNConnection(conn, false);
}
delete msg;
}
NASPlainMessage *EMMEntity::createAttachAccept() {
NASPlainMessage *msg = new NASPlainMessage("Attach-Accept");
msg->setHdr(NASUtils().createHeader(0, PlainNASMessage, EMMMessage, 0, AttachAccept));
msg->setIesArraySize(5);
/* EPS attach result */
msg->setIes(0, NASUtils().createIE(IE_V, IEType1, 0, 2)); // 2 = combined EPS/IMSI attach
/* Spare half octet */
msg->setIes(1, NASUtils().createIE(IE_V, IEType1, 0, 0));
/* T3412 value */
// 111 - timer deactivated, 00000 - timer deactivated (for tracking area update)
msg->setIes(2, NASUtils().createIE(IE_V, IEType3, 0, 224));
/* TAI list */
char *taiList = (char*)calloc(6, sizeof(char));
taiList[0] = 0; // 00 - type list, 00000 number of elements
memcpy(taiList + 1, ownerp->getPlmnId(), PLMNID_CODED_SIZE);
memcpy(taiList + 1 + PLMNID_CODED_SIZE, ownerp->getTac(), TAC_CODED_SIZE);
msg->setIes(3, NASUtils().createIE(IE_LV, IEType4, 0, 6, taiList));
/* ESM message container */
NASPlainMessage *actDefBearerReq = peer->getDefPDNConnection()->createActDefBearerRequest();
msg->encapsulate(actDefBearerReq);
msg->setEncapPos(4);
return msg;
}
void EMMEntity::processAttachAccept(NASPlainMessage *msg) {
/* ESM message container */
PDNConnection *conn = peer->getDefPDNConnection();
NASPlainMessage *smsg = check_and_cast<NASPlainMessage*>(msg->decapsulate());
if (smsg->getHdr().getMsgType() == ActDefEPSBearerCtxtReq)
conn->processActDefBearerRequest(smsg);
performStateTransition(AttachAccepted);
delete msg;
}
NASPlainMessage *EMMEntity::createAttachReject() {
NASPlainMessage *msg = new NASPlainMessage("Attach-Reject");
msg->setHdr(NASUtils().createHeader(0, PlainNASMessage, EMMMessage, 0, AttachReject));
msg->setIesArraySize(1);
/* EMM Cause */
msg->setIes(0, NASUtils().createIE(IE_V, IEType3, 0, (unsigned char)emmCause));
/* ESM message container */
// NASPlainMessage *actDefBearerReq = peer->getDefPDNConnection()->createActDefBearerRequest();
// msg->encapsulate(actDefBearerReq);
// msg->setEncapPos(4);
return msg;
}
void EMMEntity::processAttachReject(NASPlainMessage *msg) {
/* EMM Cause */
emmCause = msg->getIes(0).getValue(0);
/* ESM message container */
// PDNConnection *conn = peer->getDefPDNConnection();
// NASPlainMessage *smsg = check_and_cast<NASPlainMessage*>(msg->decapsulate());
// if (smsg->getHdr().getMsgType() == ActDefEPSBearerCtxtReq)
// conn->processActDefBearerRequest(smsg);
performStateTransition(AttachRejected);
delete msg;
}
NASPlainMessage *EMMEntity::createAttachComplete() {
NASPlainMessage *msg = new NASPlainMessage("Attach-Complete");
msg->setHdr(NASUtils().createHeader(0, PlainNASMessage, EMMMessage, 0, AttachComplete));
msg->setIesArraySize(1);
/* ESM message container */
NASPlainMessage *actDefBearerReq = peer->getDefPDNConnection()->createActDefBearerAccept();
msg->encapsulate(actDefBearerReq);
msg->setEncapPos(0);
return msg;
}
void EMMEntity::processAttachComplete(NASPlainMessage *msg) {
/* ESM message container */
PDNConnection *conn = peer->getDefPDNConnection();
NASPlainMessage *smsg = check_and_cast<NASPlainMessage*>(msg->decapsulate());
if (smsg->getHdr().getMsgType() == ActDefEPSBearerCtxtAcc)
conn->processActDefBearerAccept(smsg);
performStateTransition(AttachCompleted);
delete msg;
}
const char *EMMEntity::stateName(int state) const {
#define CASE(x) case x: s=#x; break
const char *s = "unknown";
switch (state) {
CASE(EMM_NULL);
CASE(EMM_DEREGISTERED_U);
CASE(EMM_DEREGISTERED_NORMAL_SERVICE);
CASE(EMM_DEREGISTERED_LIMITED_SERVICE);
CASE(EMM_DEREGISTERED_ATTEMPTING_TO_ATTACH);
CASE(EMM_DEREGISTERED_PLMN_SEARCH);
CASE(EMM_DEREGISTERED_NO_IMSI);
CASE(EMM_DEREGISTERED_ATTACH_NEEDED);
CASE(EMM_DEREGISTERED_NO_CELL_AVAILABLE);
CASE(EMM_REGISTERED_U);
CASE(EMM_REGISTERED_INITIATED);
CASE(EMM_REGISTERED_NORMAL_SERVICE);
CASE(EMM_REGISTERED_ATTEMPTING_TO_UPDATE);
CASE(EMM_REGISTERED_LIMITED_SERVICE);
CASE(EMM_REGISTERED_PLMN_SEARCH);
CASE(EMM_REGISTERED_UPDATE_NEEDED);
CASE(EMM_REGISTERED_ATTEMPTING_TO_UPDATE_MM);
CASE(EMM_REGISTERED_IMSI_DETACH_INITIATED);
CASE(EMM_DEREGISTERED_INITIATED_U);
CASE(EMM_TRACKING_AREA_UPDATING_INITIATED);
CASE(EMM_SERVICE_REQUEST_INITIATED);
CASE(EMM_DEREGISTERED_N);
CASE(EMM_COMMON_PROCEDURE_INITIATED);
CASE(EMM_REGISTERED_N);
CASE(EMM_DEREGISTERED_INITIATED_M);
}
return s;
#undef CASE
}
const char *EMMEntity::statusName() const {
#define CASE(x) case x: s=#x; break
const char *s = "unknown";
switch (epsUpdSt) {
CASE(EU1_UPDATED);
CASE(EU2_NOT_UPDATED);
CASE(EU3_ROAMING_NOT_ALLOWED);
}
return s;
#undef CASE
}
const char *EMMEntity::eventName(int event) {
#define CASE(x) case x: s=#x; break
const char *s = "unknown";
switch (event) {
CASE(EnableS1Mode);
CASE(NoUSIM);
CASE(CellFoundPermittedPLMN);
CASE(SwitchOn);
CASE(AttachRequested);
CASE(AttachAccepted);
CASE(AttachRejected);
CASE(AttachCompleted);
}
return s;
#undef CASE
}
void EMMEntity::setModule(NAS *module) {
this->module = module;
}
NAS *EMMEntity::getModule() {
return module;
}
void EMMEntity::setOwner(Subscriber *ownerp) {
ownerp->setEmmEntity(this);
this->ownerp = ownerp;
}
Subscriber *EMMEntity::getOwner() {
return ownerp;
}
void EMMEntity::startT3410() {
if (t3410 == NULL) {
t3410 = new cMessage("T3410");
t3410->setContextPointer(this);
}
module->scheduleAt(simTime() + T3410_TIMEOUT, t3410);
if (t3402 != NULL)
module->cancelEvent(t3402);
if (t3411 != NULL)
module->cancelEvent(t3411);
}
void EMMEntity::setPeer(ESMEntity *peer) {
this->peer = peer;
}
ESMEntity *EMMEntity::getPeer() {
return peer;
}
std::string EMMEntity::info(int tabs) const {
std::stringstream out;
if (imsi != NULL) {
for (int i = 0; i < tabs; i++) out << "\t";
out << "imsi:" << LTEUtils().toASCIIString(imsi, IMSI_CODED_SIZE) << "\n";
}
if (epsUpdSt != -1) {
for (int i = 0; i < tabs; i++) out << "\t";
out << "epsUpdSt:" << statusName() << "\n";
}
if (fsm != NULL) {
for (int i = 0; i < tabs; i++) out << "\t";
out << "emmSt:" << stateName(fsm->getState()) << "\n";
}
return out.str();
}
//
// Copyright (C) 2012 Calin Cerchez
//
// 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/.
//
#ifndef EMMENTITY_H_
#define EMMENTITY_H_
#include <omnetpp.h>
#include "NASMessage_m.h"
#include "PDNConnection.h"
#define T3410_TIMEOUT 20
class NAS;
class Subscriber;
enum EMMSublayerState {
/* for UE */
EMM_NULL = FSM_Steady(0),
EMM_DEREGISTERED_U = FSM_Steady(1),
EMM_DEREGISTERED_NORMAL_SERVICE = FSM_Steady(2),
EMM_DEREGISTERED_LIMITED_SERVICE = FSM_Steady(3),
EMM_DEREGISTERED_ATTEMPTING_TO_ATTACH = FSM_Steady(4),
EMM_DEREGISTERED_PLMN_SEARCH = FSM_Steady(5),
EMM_DEREGISTERED_NO_IMSI = FSM_Steady(6),
EMM_DEREGISTERED_ATTACH_NEEDED = FSM_Steady(7),
EMM_DEREGISTERED_NO_CELL_AVAILABLE = FSM_Steady(8),
EMM_REGISTERED_U = FSM_Steady(9),
EMM_REGISTERED_INITIATED = FSM_Steady(10),
EMM_REGISTERED_NORMAL_SERVICE = FSM_Steady(11),
EMM_REGISTERED_ATTEMPTING_TO_UPDATE = FSM_Steady(12),
EMM_REGISTERED_LIMITED_SERVICE = FSM_Steady(13),
EMM_REGISTERED_PLMN_SEARCH = FSM_Steady(14),
EMM_REGISTERED_UPDATE_NEEDED = FSM_Steady(15),
EMM_REGISTERED_NO_CELL_AVAILABLE = FSM_Steady(16),
EMM_REGISTERED_ATTEMPTING_TO_UPDATE_MM = FSM_Steady(17),
EMM_REGISTERED_IMSI_DETACH_INITIATED = FSM_Steady(18),
EMM_DEREGISTERED_INITIATED_U = FSM_Steady(19),
EMM_TRACKING_AREA_UPDATING_INITIATED = FSM_Steady(20),
EMM_SERVICE_REQUEST_INITIATED = FSM_Steady(21),
/* for MME */
EMM_DEREGISTERED_N = FSM_Steady(22),
EMM_COMMON_PROCEDURE_INITIATED = FSM_Steady(23),
EMM_REGISTERED_N = FSM_Steady(24),
EMM_DEREGISTERED_INITIATED_M = FSM_Steady(25)
};
enum EMMSublayerEvent {
/* for UE */
EnableS1Mode,
SwitchOn,
NoUSIM,
CellFoundPermittedPLMN,
AttachRequested,
/* for MME and UE */
AttachAccepted,
AttachRejected,
/* for MME */
AttachCompleted,
};
enum EPSUpdateStatus {
EU1_UPDATED,
EU2_NOT_UPDATED,
EU3_ROAMING_NOT_ALLOWED
};
/*
* Class for NAS EMM entity.
*/
class EMMEntity : public cPolymorphic {
private:
unsigned char attCounter;
unsigned char tracAreaUpdCounter;
// used for message creating and processing
unsigned char appType;
unsigned char nasKey;
char emmCause;
char *imsi;
unsigned tmsi;
char *ueNetworkCapability;
cFSM *fsm;
char epsUpdSt;
cMessage *t3402;
cMessage *t3410;
cMessage *t3411;
cMessage *t3450;
NAS *module;
Subscriber *ownerp;
ESMEntity *peer;
public:
EMMEntity();
EMMEntity(unsigned char appType);
virtual ~EMMEntity();
/*
* Method for initializing a EMM entity. Basically all parameters are set to
* their default values.
*/
void init();
/*
* Setter methods.
*/
void setOwner(Subscriber *ownerp);
void setModule(NAS *module);
void setImsi(char *imsi) { this->imsi = imsi; }
void setTmsi(unsigned tmsi) { this->tmsi = tmsi; }
void setPeer(ESMEntity *peer);
void setEmmCause(int emmCause) { this->emmCause = emmCause; }
/*
* Getter methods.
*/
unsigned char getAppType() { return appType; }
NAS *getModule();
Subscriber *getOwner();
char *getImsi() { return imsi; }
unsigned getTmsi() { return tmsi; }
ESMEntity *getPeer();
int getState() { return fsm->getState(); }
cFSM *getFSM() { return fsm; }
/*
* Utility methods for state processing and printing.
*/
void performStateTransition(EMMSublayerEvent event);
void stateEntered();
const char *stateName(int state) const;
const char *statusName() const;
const char *eventName(int event);
/*
* Methods for processing and creating of NAS messages, which are related to
* EMM entity. These messages are related to user equipment mobility.
*/
NASPlainMessage *createAttachRequest();
NASPlainMessage *createAttachAccept();
NASPlainMessage *createAttachReject();
NASPlainMessage *createAttachComplete();
void processAttachRequest(NASPlainMessage *msg);
void processAttachAccept(NASPlainMessage *msg);
void processAttachReject(NASPlainMessage *msg);
void processAttachComplete(NASPlainMessage *msg);
/*
* Method for starting T3410 timer. This will cancel timers T3402 and T3411.
*/
void startT3410();
/*
* Method for printing information about EMM entity for a subscriber.
*/
std::string info(int tabs) const;
};
#endif /* EMMCONTEXT_H_ */
//
// 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/.
//
#include "ESMEntity.h"
#include "EMMEntity.h"
#include "NAS.h"
#include "NASUtils.h"
#include "DiameterApplication.h"
#include "GTPMessage_m.h"
#include "NASSerializer.h"
ESMEntity::ESMEntity() {
init();
}
ESMEntity::ESMEntity(unsigned char appType) {
// TODO Auto-generated constructor stub
init();
this->appType = appType;
}
ESMEntity::~ESMEntity() {
// TODO Auto-generated destructor stub
delPDNConnection(0, conns.size());
}
void ESMEntity::init() {
ownerp = NULL;
appType = 0;
defConn = NULL;
connIds = 0;
bearerIds = 0;
peer = NULL;
module = NULL;
}
void ESMEntity::setOwner(Subscriber *ownerp) {
ownerp->setEsmEntity(this);
this->ownerp = ownerp;
}
Subscriber *ESMEntity::getOwner() {
return ownerp;
}
void ESMEntity::addPDNConnection(PDNConnection *conn, bool def) {
conn->setOwner(this);
if (def == true)
defConn = conn;
conns.push_back(conn);
}
void ESMEntity::delPDNConnection(unsigned start, unsigned end) {
PDNConnections::iterator first = conns.begin() + start;
PDNConnections::iterator last = conns.begin() + end;
PDNConnections::iterator i = first;
for (;i != last; ++i) {
if (*i == defConn)
defConn = NULL;
delete *i;
}
conns.erase(first, last);
}
AVP *ESMEntity::createAPNConfigProfAVP() {
if (conns.size() > 0) {
std::vector<AVP*> apnConfigProfVec;
apnConfigProfVec.push_back(DiameterUtils().createUnsigned32AVP(AVP_ContextIdentifier, 1, 0, 0, TGPP, defConn->getId()));
apnConfigProfVec.push_back(DiameterUtils().createInteger32AVP(AVP_AllAPNConfigInclInd, 1, 0, 0, TGPP, All_APN_CONFIGURATIONS_INCLUDED));
for (unsigned i = 0; i < conns.size(); i++) {
PDNConnection *conn = conns.at(i);
apnConfigProfVec.push_back(conn->createAPNConfigAVP());
}
AVP *apnConfigProf = DiameterUtils().createGroupedAVP(AVP_APNConfigProfile, 1, 0, 0, TGPP, apnConfigProfVec);
DiameterUtils().deleteGroupedAVP(apnConfigProfVec);
return apnConfigProf;
}
return NULL;
}
bool ESMEntity::processAPNConfigProfAVP(AVP *apnConfigProf) {
std::vector<AVP*> apnConfigProfVec = DiameterUtils().processGroupedAVP(apnConfigProf);
AVP *ctxtId = DiameterUtils().findAVP(AVP_ContextIdentifier, apnConfigProfVec);
if (ctxtId == NULL) {
EV << "DiameterS6a: Missing ContextIdentifier AVP.\n";
return false;
}
unsigned defId = DiameterUtils().processUnsigned32AVP(ctxtId);
std::vector<AVP*> apnConfigs = DiameterUtils().findAVPs(AVP_APNConfig, apnConfigProfVec);
for (unsigned i = 0; i < apnConfigs.size(); i++) {
std::vector<AVP*> apnConfig = DiameterUtils().processGroupedAVP(apnConfigs[i]);
if (i < conns.size()) {
PDNConnection *conn = conns.at(i);
if (!conn->processAPNConfigAVP(apnConfig))
return false;
if (conn->getId() == defId)
this->defConn = conn;
} else {
/* TODO */
// add additional pdn connections received from HSS
}
}
DiameterUtils().deleteGroupedAVP(apnConfigProfVec);
return true;
}
void ESMEntity::setPeer(EMMEntity *peer) {
this->peer = peer;
}
EMMEntity *ESMEntity::getPeer() {
return peer;
}
void ESMEntity::setModule(NAS *module) {
this->module = module;
}
std::string ESMEntity::info(int tabs) const {
std::stringstream out;
if (conns.size() > 0) {
for (int i = 0; i < tabs; i++) out << "\t";
out << "pdnConns:{\n";
for (unsigned j = 0; j < conns.size(); j++) {
for (int i = 0; i < tabs + 1; i++) out << "\t";
out << "pdnConn:{\n" << conns.at(j)->info(tabs + 2);
for (int i = 0; i < tabs + 1; i++) out << "\t";
out << "}\n";
}
for (int i = 0; i < tabs; i++) out << "\t";
out << "}\n";
}
return out.str();
}
//
// 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/.
//
#ifndef ESMENTITY_H_
#define ESMENTITY_H_
#include <omnetpp.h>
#include "PDNConnection.h"
#include "NASMessage_m.h"
class Subscriber;
class EMMEntity;
class NAS;
class ESMEntity {
private:
unsigned connIds;
unsigned char bearerIds;
unsigned char appType;
Subscriber *ownerp;
PDNConnection *defConn;
typedef std::vector<PDNConnection*> PDNConnections;
PDNConnections conns;
NAS *module;
EMMEntity *peer;
public:
ESMEntity();
ESMEntity(unsigned char appType);
virtual ~ESMEntity();
/* init */
void init();
/* setter */
void setOwner(Subscriber *owernp);
void setDefPDNConnection(PDNConnection *defConn) { this->defConn = defConn; }
void setPeer(EMMEntity *peer);
void setModule(NAS *module);
/* getter */
Subscriber *getOwner();
unsigned char getAppType() { return appType; }
PDNConnection *getDefPDNConnection() { return defConn; }
EMMEntity *getPeer();
unsigned size() { return conns.size(); }
/* pdn connection */
void addPDNConnection(PDNConnection *conn, bool def);
void delPDNConnection(unsigned start, unsigned end);
/* gen bearer ids */
unsigned char genBearerId() { return ++bearerIds; }
unsigned genPDNConnectionId() { return ++connIds; }
/* diameter avp */
AVP *createAPNConfigProfAVP();
bool processAPNConfigProfAVP(AVP *apnConfigProf);
std::string info(int tabs) const;
};
#endif /* ESMENTITY_H_ */
//
// 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/.
//
#include "NAS.h"
#include "LTEUtils.h"
#include "PhyControlInfo_m.h"
#include "S1APControlInfo_m.h"
#include "S1APConstant.h"
#include "NASSerializer.h"
#include "PDNConnection.h"
#include "NASUtils.h"
#include "InterfaceTableAccess.h"
#include "IPv4InterfaceData.h"
#include "RoutingTableAccess.h"
Define_Module(NAS)
NAS::NAS() {
// TODO Auto-generated constructor stub
appType = RELAY_APPL_TYPE;
}
NAS::~NAS() {
// TODO Auto-generated destructor stub
// if (sub != NULL)
// delete emm;
}
void NAS::initialize(int stage) {
if (stage == 4) {
subT = SubscriberTableAccess().get();
const char *fileName = par("configFile");
if (fileName != NULL && (strcmp(fileName, "")))
this->loadConfigFromXML(fileName);
ift=InterfaceTableAccess().get();
rt=RoutingTableAccess().get();
nb = NotificationBoardAccess().get();
nb->subscribe(this, NF_SUB_AUTH_ACK);
nb->subscribe(this, NF_SUB_AUTH_NACK);
nb->subscribe(this, NF_SUB_PDN_ACK);
}
}
void NAS::handleMessage(cMessage *msg) {
if (appType == RELAY_APPL_TYPE) {
if (msg->isSelfMessage()) {
msg->setName("Relay-Message");
// NASRelay *relay = (NASRelay*)msg->getContextPointer();
// relay->processTimer(msg);
} else if (msg->arrivedOn("radioIn")) {
EV << "NAS-RELAY: Received message from radio. Relaying message.\n";
handleMessageFromRadio(msg);
} else {
EV << "NAS-RELAY: Received message from S1AP. Relaying message.\n";
handleMessageFromS1AP(msg);
}
} else if (appType == MME_APPL_TYPE) {
msg->setName("MME-Message");
if (msg->isSelfMessage()) {
} else {
EV << "NAS-MME: Received message from S1AP. Processing message.\n";
handleMessageFromS1AP(msg);
}
} else if (appType == UE_APPL_TYPE) {
msg->setName("UE-Message");
if (msg->isSelfMessage()) {
} else {
EV << "NAS-UE: Received message from radio. Processing message.\n";
handleMessageFromRadio(msg);
}
}
}
void NAS::handleMessageFromS1AP(cMessage *msg) {
S1APControlInfo *ctrl = dynamic_cast<S1APControlInfo *>(msg->removeControlInfo());
char *buf = (char*)calloc(ctrl->getValueArraySize(), sizeof(char));
char *p = buf;
for (unsigned i = 0; i < ctrl->getValueArraySize(); i++)
buf[i] = ctrl->getValue(i);
Subscriber *sub = subT->findSubscriberForId(ctrl->getSubEnbId(), ctrl->getSubMmeId());
if (sub == NULL) {
EV << "NAS: Unknown subscriber. Dropping message.\n";
goto end;
}
{
NASPlainMessage *nmsg = new NASPlainMessage();
NASHeader hdr = NASSerializer().parseHeader(p);
if (!hdr.getLength()) {
EV << "NAS: Message decoding error. Dropping message.\n";
goto end;
}
p += hdr.getLength();
nmsg->setHdr(hdr);
switch(hdr.getMsgType()) {
case AttachRequest: {
nmsg->setName("Attach-Request");
if (!NASUtils().parseAttachRequest(nmsg, p)) {
EV << "NAS: Message processing error. Dropping message.\n";
goto end;
}
sub->setMmeId(subT->genMmeId());
sub->initEntities(appType);
EMMEntity *emm = sub->getEmmEntity();
emm->setModule(this);
ESMEntity *esm = sub->getEsmEntity();
esm->setModule(this);
emm->processAttachRequest(nmsg);
sub->setStatus(SUB_PENDING);
nb->fireChangeNotification(NF_SUB_NEEDS_AUTH, sub);
break;
}
case AttachAccept: {
nmsg->setName("Attach-Accept");
if (!NASUtils().parseAttachAccept(nmsg, p)) {
EV << "NAS: Message parsing error. Dropping message.\n";
goto end;
}
sub->setStatus(SUB_ACTIVE);
sendToRadio(nmsg, sub->getChannelNr());
break;
}
case AttachReject: {
nmsg->setName("Attach-Reject");
if (!NASUtils().parseAttachReject(nmsg, p)) {
EV << "NAS: Message parsing error. Dropping message.\n";
goto end;
}
sub->setStatus(SUB_INACTIVE);
sendToRadio(nmsg, sub->getChannelNr());
break;
}
case AttachComplete: {
nmsg->setName("Attach-Complete");
if (!NASUtils().parseAttachComplete(nmsg, p)) {
EV << "NAS: Message parsing error. Dropping message.\n";
goto end;
}
sub->getEmmEntity()->processAttachComplete(nmsg);
break;
}
default:;
}
}
end:
delete msg;
delete ctrl;
}
void NAS::handleMessageFromRadio(cMessage *msg) {
NASPlainMessage *nmsg = check_and_cast<NASPlainMessage*>(msg);
PhyControlInfo *ctrl = dynamic_cast<PhyControlInfo *>(nmsg->removeControlInfo());
Subscriber *sub = subT->findSubscriberForChannel(ctrl->getChannelNumber());
if (appType == RELAY_APPL_TYPE) {
if (sub == NULL) {
sub = new Subscriber();
sub->initEntities(appType);
// only dummy PDN connection to store the UE bearer contexts
PDNConnection *conn = new PDNConnection();
conn->setOwner(sub->getEsmEntity());
sub->getEsmEntity()->addPDNConnection(conn, true);
sub->setChannelNr(ctrl->getChannelNumber());
sub->setEnbId(subT->genEnbId());
sub->setMmeId(0);
sub->setStatus(SUB_PENDING);
subT->push_back(sub);
}
sendToS1AP(nmsg, sub->getEnbId(), sub->getMmeId());
} else {
if (sub == NULL) {
delete nmsg;
return;
}
// NASUtils().printMessage(nmsg);
switch(nmsg->getHdr().getMsgType()) {
case AttachAccept: {
EMMEntity *emm = sub->getEmmEntity();
ESMEntity *esm = sub->getEsmEntity();
emm->processAttachAccept(nmsg);
InterfaceEntry *entry = ift->getInterfaceByName("UERadioInterface");
if(entry)
{
entry->ipv4Data()->setIPAddress(esm->getDefPDNConnection()->getSubscriberAddress().get4());
entry->setMACAddress(MACAddress::generateAutoAddress());
entry->setMtu(1500);
IPRoute *route=new IPRoute();
route->setInterface(entry);
rt->addRoute(route);
// nb->fireChangeNotification(NF_INTERFACE_CONFIG_CHANGED, route);
}
break;
}
case AttachReject: {
EMMEntity *emm = sub->getEmmEntity();
emm->processAttachReject(nmsg);
break;
}
default:
delete nmsg;
}
}
delete ctrl;
}
void NAS::sendToS1AP(NASPlainMessage *nmsg, unsigned subEnbId, unsigned subMmeId) {
cMessage *msg = new cMessage(nmsg->getName());
S1APControlInfo *ctrl = new S1APControlInfo();
ctrl->setSubEnbId(subEnbId);
ctrl->setSubMmeId(subMmeId);
switch(nmsg->getHdr().getMsgType()) {
case AttachRequest:
ctrl->setProcId(id_initialUEMessage);
break;
case AttachAccept:
ctrl->setProcId(id_InitialContextSetup);
break;
case AttachReject:
ctrl->setProcId(id_downlinkNASTransport);
break;
case AttachComplete:
ctrl->setProcId(id_uplinkNASTransport);
break;
default:;
}
char *nasPdu;
unsigned nasPduLen = NASSerializer().serialize(nmsg, nasPdu);
ctrl->setValueArraySize(nasPduLen);
for (unsigned i = 0; i < ctrl->getValueArraySize(); i++)
ctrl->setValue(i, nasPdu[i]);
msg->setControlInfo(ctrl);
delete nmsg;
send(msg, gate("s1apOut"));
}
void NAS::sendToRadio(NASPlainMessage *nmsg, int channelNr) {
PhyControlInfo *ctrl = new PhyControlInfo();
ctrl->setChannelNumber(channelNr);
ctrl->setBitrate(2e6);
nmsg->setControlInfo(ctrl);
send(nmsg, gate("radioOut"));
}
void NAS::loadConfigFromXML(const char *filename) {
cXMLElement* config = ev.getXMLDocument(filename);
if (config == NULL)
error("NAS: Cannot read configuration from file: %s", filename);
cXMLElement* nasNode = config->getElementByPath("NAS");
if (nasNode == NULL)
error("NAS: No configuration for NAS");
if (!nasNode->getAttribute("appType"))
error("NAS: No <appType> for NAS");
appType = atoi(nasNode->getAttribute("appType"));
if (appType == UE_APPL_TYPE) {
/* TODO */
// no cell available
channelNumber = par("channelNumber");
Subscriber *sub = new Subscriber();
sub->setChannelNr(channelNumber);
sub->initEntities(appType);
subT->push_back(sub);
loadESMConfigFromXML(*nasNode);
loadEMMConfigFromXML(*nasNode);
} else if (appType == RELAY_APPL_TYPE) {
} else {
}
}
void NAS::loadEMMConfigFromXML(const cXMLElement &nasNode) {
EMMEntity *emm = subT->at(0)->getEmmEntity();
emm->setModule(this);
// go to EMM_DEREGISTERED_PLMN_SEARCH
emm->performStateTransition(SwitchOn);
const char *imsi = nasNode.getAttribute("imsi");
if (!imsi) {
emm->performStateTransition(NoUSIM);
return;
}
emm->setImsi(LTEUtils().toIMSI(imsi));
// go to EMM_DEREGISTERED_NORMAL_SERVICE
emm->performStateTransition(CellFoundPermittedPLMN);
/* TODO */
// limited-service
/* TODO */
// manual network mode
}
void NAS::loadESMConfigFromXML(const cXMLElement &nasNode) {
ESMEntity *esm = subT->at(0)->getEsmEntity();
esm->setModule(this);
PDNConnection *conn = new PDNConnection(esm);
esm->addPDNConnection(conn, true);
}
void NAS::receiveChangeNotification(int category, const cPolymorphic *details) {
Enter_Method_Silent();
if (category == NF_SUB_AUTH_ACK) {
EV << "NAS: Received NF_SUB_AUTH_ACK notification. Processing notification.\n";
Subscriber *sub = check_and_cast<Subscriber*>(details);
nb->fireChangeNotification(NF_SUB_NEEDS_PDN, sub->getDefaultPDNConn());
} else if (category == NF_SUB_AUTH_NACK) {
EV << "NAS: Received NF_SUB_AUTH_NACK notification. Processing notification.\n";
Subscriber *sub = check_and_cast<Subscriber*>(details);
EMMEntity *emm = sub->getEmmEntity();
emm->performStateTransition(AttachRejected);
} else if (category == NF_SUB_PDN_ACK) {
EV << "NAS: Received NF_SUB_PDN_ACK notification. Processing notification.\n";
PDNConnection *conn = check_and_cast<PDNConnection*>(details);
EMMEntity *emm = conn->getOwner()->getPeer();
if (emm->getState() == EMM_DEREGISTERED_N) {
emm->performStateTransition(AttachAccepted);
}
}
}
//
// 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/.
//
#ifndef NAS_H_
#define NAS_H_
#include <omnetpp.h>
#include "NASMessage_m.h"
#include "SubscriberTableAccess.h"
#include "NotificationBoard.h"
#include "IInterfaceTable.h"
#include "RoutingTable.h"
//#include "S1APConnectionTableAccess.h"
//#include "NASRelayTable.h"
#define UE_APPL_TYPE 0
#define MME_APPL_TYPE 1
#define RELAY_APPL_TYPE 2
#define SEND_RETRY_TIMER 2
class NAS : public cSimpleModule, public INotifiable {
private:
NotificationBoard *nb; // only for MME
unsigned char appType;
int channelNumber;
SubscriberTable *subT;
IInterfaceTable *ift;
IRoutingTable *rt;
public:
NAS();
virtual ~NAS();
/* module */
virtual int numInitStages() const { return 5; }
virtual void initialize(int stage);
void loadConfigFromXML(const char *filename);
void loadEMMConfigFromXML(const cXMLElement &nasNode);
void loadESMConfigFromXML(const cXMLElement &nasNode);
virtual void handleMessage(cMessage *msg);
/* getter */
int getChannelNumber() { return channelNumber; }
/* message */
void handleMessageFromS1AP(cMessage *msg);
void handleMessageFromRadio(cMessage *msg);
void sendToS1AP(NASPlainMessage *nmsg, unsigned subEnbId, unsigned subMmeId);
void sendToRadio(NASPlainMessage *nmsg, int channelNr);
/* notification */
virtual void receiveChangeNotification(int category, const cPolymorphic *details);
/* timers */
void dropTimer(cMessage *timer) { drop(timer); }
void takeTimer(cMessage *timer) { take(timer); }
// S1APConnection *findConnection() { return s1apT->findConnection(); }
};
#endif /* NAS_H_ */
//
// Copyright (C) 2012 Calin Cerchez
//
// 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/.
//
package inet.applications.nas;
simple NAS
{
parameters:
@display("i=block/control");
string configFile = default("");
int channelNumber = default(0);
gates:
input radioIn;
output radioOut;
input s1apIn;
output s1apOut;
}
\ No newline at end of file
//
// Copyright (C) 2012 Calin Cerchez
//
// 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/.
//
cplusplus {{
#define NAS_ESM_HEADER_SIZE 3
#define NAS_EMM_HEADER_SIZE 2
}}
enum InfoElemFormats
{
IE_V = 1;
IE_LV = 2;
IE_LVE = 3;
IE_TV = 4;
IE_TLV = 5;
IE_TLVE = 6;
}
enum InfoElemTypes
{
IEType1 = 1; // TV or V with value length 1/2
IEType2 = 2; // T with value length 0
IEType3 = 3; // V or TV with value fixed length >= 1
IEType4 = 4; // LV or TLV with value variable length < 255
IEType6 = 6; // TLVE and LVE with value variable length > 255
}
enum ProtocolDiscriminator
{
ESMMessage = 2;
EMMMessage = 7;
}
enum SecurityHeaderTypes
{
PlainNASMessage = 0;
}
enum NASMessageTypes
{
AttachRequest = 65;
AttachAccept = 66;
AttachComplete = 67;
AttachReject = 68;
ActDefEPSBearerCtxtReq = 193;
ActDefEPSBearerCtxtAcc = 194;
PDNConnectivityRequest = 208;
}
enum RequestTypeValues
{
InitialRequest = 1;
Handover = 2;
Unused_RequestType = 3;
Emergency = 4;
}
enum EPSAttachTypes
{
EPSAttach = 1;
CombinedAttach = 2;
EmergencyAttach = 6;
Reserved_EPSAttach = 7;
}
enum EPSMobileIdentityTypes
{
IMSI_ID = 1;
GUTI_ID = 6;
IMEI_ID = 3;
}
enum NASInfoElemTypes
{
EPSMobileId = 50;
}
enum EMMCauses
{
IMSIUnknownInHSS = 2;
IllegalUE = 3;
EPSServNotAllowed = 7;
EPSServNonEPSServNotAllowed = 8;
}
class NASHeader
{
unsigned char epsBearerId; // for ESM
unsigned char secHdrType; // for EMM
unsigned char protDiscr;
unsigned char procTransId; // only for ESM
unsigned char msgType; // 01------ for EMM
// 11------ for ESM
unsigned char length = 0; // only for serializing/parsing usage
}
class NASInfoElem
{
unsigned char format;
unsigned char ieType;
unsigned char type;
char value[]; // length = value array size
}
packet NASPlainMessage
{
NASHeader hdr;
NASInfoElem ies[];
int encapPos; // position of encapsulated packet
}
\ No newline at end of file
//
// 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/.
//
/* See 3GPP TS 24007 chapter 11.2 */
#include "NASSerializer.h"
#include "NASUtils.h"
#include <platdep/sockets.h>
NASSerializer::NASSerializer() {
// TODO Auto-generated constructor stub
shift = 0;
}
NASSerializer::~NASSerializer() {
// TODO Auto-generated destructor stub
}
unsigned NASSerializer::calcLength(NASPlainMessage *msg) {
unsigned len = msg->getHdr().getMsgType() & 0x80 ? NAS_ESM_HEADER_SIZE : NAS_EMM_HEADER_SIZE;
for (unsigned i = 0; i < msg->getIesArraySize(); i++) {
NASInfoElem ie = msg->getIes(i);
switch(ie.getIeType()) {
case IEType1:
if (ie.getFormat() == IE_TV)
len++;
else if (ie.getFormat() == IE_V) {
len += (shift + 1) % 2;
shift = (shift + 1) % 2;
}
break;
case IEType2:
len++;
break;
case IEType3:
len += ie.getValueArraySize();
if (ie.getFormat() == IE_TV)
len++;
break;
case IEType4:
len += ie.getValueArraySize() + 1;
if (ie.getFormat() == IE_TLV)
len++;
break;
case IEType6:
len += ie.getValueArraySize() + 2;
if (ie.getFormat() == IE_TLVE)
len++;
break;
default:;
}
}
return len;
}
unsigned NASSerializer::serializeHeader(NASHeader hdr, char *p) {
if (hdr.getMsgType() & 0x80) { // is ESM message
*((unsigned char*)(p++)) = (hdr.getEpsBearerId() << 4) | (hdr.getProtDiscr());
*((unsigned char*)p++) = hdr.getProcTransId();
} else { // for EMM message
*((unsigned char*)(p++)) = (hdr.getSecHdrType() << 4) | (hdr.getProtDiscr());
}
*((unsigned char*)p++) = hdr.getMsgType();
return hdr.getLength();
}
NASHeader NASSerializer::parseHeader(char *p) {
NASHeader hdr = NASHeader();
hdr.setProtDiscr(*((unsigned char*)(p)) & 0x0f);
if (hdr.getProtDiscr() == ESMMessage) { // is ESM message
hdr.setEpsBearerId((*((unsigned char*)(p++)) >> 4) & 0x0f);
hdr.setLength(NAS_ESM_HEADER_SIZE);
hdr.setProcTransId(*((unsigned char*)p++));
} else if (hdr.getProtDiscr() == EMMMessage) { // for EMM message
hdr.setSecHdrType((*((unsigned char*)(p++)) >> 4) & 0x0f);
hdr.setLength(NAS_EMM_HEADER_SIZE);
}
hdr.setMsgType(*((unsigned char*)p++));
return hdr;
}
unsigned NASSerializer::serializeIE(NASInfoElem ie, char *p) {
char *begin = p;
switch(ie.getIeType()) {
case IEType1:
if (ie.getFormat() == IE_TV) {
*((unsigned char*)(p++)) = (ie.getType() << 4) | (ie.getValue(0) & 0x0f);
} else if (ie.getFormat() == IE_V) { // shifting only for type 1 (after one IE type 1 follows another with type 1)
*((unsigned char*)(p)) += ((unsigned char)ie.getValue(0)) << (((shift + 1) % 2) * 4);
p += shift % 2;
shift = (shift + 1) % 2;
}
break;
case IEType2:
*((unsigned char*)(p++)) = ie.getType();
break;
case IEType3:
if (ie.getFormat() == IE_TV)
*((unsigned char*)(p++)) = ie.getType();
for (unsigned i = 0; i < ie.getValueArraySize(); i++)
*((char*)(p++)) = ie.getValue(i);
break;
case IEType4:
if (ie.getFormat() == IE_TLV)
*((unsigned char*)(p++)) = ie.getType();
*((unsigned char*)(p++)) = ie.getValueArraySize();
for (unsigned i = 0; i < ie.getValueArraySize(); i++)
*((char*)(p++)) = ie.getValue(i);
break;
case IEType6:
if (ie.getFormat() == IE_TLVE)
*((unsigned char*)(p++)) = ie.getType();
*((unsigned short*)p) = ntohs(ie.getValueArraySize());
p += 2;
for (unsigned i = 0; i < ie.getValueArraySize(); i++)
*((char*)(p++)) = ie.getValue(i);
break;
default:;
}
return p - begin;
}
NASInfoElem NASSerializer::parseIE(char *p, unsigned char format, unsigned char ieType, unsigned short length) {
NASInfoElem ie = NASInfoElem();
ie.setIeType(ieType);
ie.setFormat(format);
ie.setValueArraySize(length);
char *begin = p;
switch(ie.getIeType()) {
case IEType1:
ie.setValueArraySize(1);
if (ie.getFormat() == IE_TV) {
ie.setType((*((unsigned char*)(p)) >> 4) & 0x0f);
ie.setValue(0, *((unsigned char*)(p++)) & 0x0f);
} else if (ie.getFormat() == IE_V) { // shifting only for type 1 (after one IE type 1 follows another with type 1)
ie.setValue(0, *((unsigned char*)(p)) >> (((shift + 1) % 2) * 4) & 0x0f);
p += shift % 2;
shift = (shift + 1) % 2;
}
break;
case IEType2:
ie.setType(*((unsigned char*)(p++)));
break;
case IEType3:
if (ie.getFormat() == IE_TV)
ie.setType(*((unsigned char*)(p++)));
for (unsigned i = 0; i < ie.getValueArraySize(); i++)
ie.setValue(i, *((char*)(p++)));
break;
case IEType4:
if (ie.getFormat() == IE_TLV)
ie.setType(*((unsigned char*)(p++)));
ie.setValueArraySize(*((unsigned char*)(p++)));
for (unsigned i = 0; i < ie.getValueArraySize(); i++)
ie.setValue(i, *((char*)(p++)));
break;
case IEType6:
if (ie.getFormat() == IE_TLVE)
ie.setType(*((unsigned char*)(p++)));
ie.setValueArraySize(ntohs(*((unsigned short*)p)));
p += 2;
for (unsigned i = 0; i < ie.getValueArraySize(); i++)
ie.setValue(i, *((char*)(p++)));
break;
default:;
}
skip = p - begin;
return ie;
}
unsigned NASSerializer::serialize(NASPlainMessage *msg, char *&buffer) {
NASPlainMessage *encMsg = NULL;
if (msg->getEncapsulatedPacket() != NULL)
encMsg = check_and_cast<NASPlainMessage*>(msg->decapsulate());
unsigned len = calcLength(msg);
int encPos = -1;
if (encMsg != NULL) {
len += calcLength(encMsg) + 2;
encPos = msg->getEncapPos();
}
buffer = (char*)calloc(len, sizeof(char));
char *p = buffer;
p += serializeHeader(msg->getHdr(), p);
for (unsigned i = 0; i < msg->getIesArraySize(); i++) {
if ((i == (unsigned)encPos) && (encPos != -1)) {
char *esmCont;
unsigned esmContLen = NASSerializer().serialize(encMsg, esmCont);
NASInfoElem ie = NASUtils().createIE(IE_LVE, IEType6, 0, esmContLen, esmCont);
p += serializeIE(ie, p);
}
p += serializeIE(msg->getIes(i), p);
}
delete encMsg;
return len;
}
//NASPlainMessage *NASSerializer::parse(char *buffer, unsigned len) {
// NASPlainMessage *msg = new NASPlainMessage();
// char *p = buffer;
// NASHeader hdr = parseHeader(p);
// if (!hdr.getLength())
// return NULL;
// p += hdr.getLength();
// msg->setHdr(hdr);
// switch(hdr.getMsgType()) {
// case AttachRequest:
// msg->setIesArraySize(5);
// msg->setName("Attach-Request");
// /* NAS key set identifier */
// msg->setIes(0, NASUtils().createIE(IE_V, IEType1));
//
// /* EPS attach type */
// msg->setIes(1, NASUtils().createIE(IE_V, IEType1));
//
// /* EPS mobile identity */
// msg->setIes(2, NASUtils().createIE(IE_LV, IEType4));
//
// /* UE network capability */
// msg->setIes(3, NASUtils().createIE(IE_LV, IEType4));
//
// /* ESM message container */
// msg->setIes(4, NASUtils().createIE(IE_LVE, IEType6));
// break;
// case PDNConnectivityRequest:
// break;
// default:;
// }
// for (unsigned i = 0; i < msg->getIesArraySize(); i++) {
// NASInfoElem ie = msg->getIes(i);
// p += parseIE(&ie, p);
// }
// return msg;
//}
//
// 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/.
//
#ifndef NASSERIALIZER_H_
#define NASSERIALIZER_H_
#include "NASMessage_m.h"
class NASSerializer {
private:
unsigned char shift;
unsigned serializeHeader(NASHeader hdr, char *p);
unsigned serializeIE(NASInfoElem ie, char *p);
unsigned calcLength(NASPlainMessage *msg);
public:
unsigned short skip;
NASSerializer();
virtual ~NASSerializer();
unsigned serialize(NASPlainMessage *msg, char *&buffer);
NASHeader parseHeader(char *p);
NASInfoElem parseIE(char *p, unsigned char format, unsigned char ieType, unsigned short length = 0);
// NASPlainMessage *parse(char *buffer, unsigned len);
};
#endif /* NASSERIALIZER_H_ */
//
// 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/.
//
#include "NASUtils.h"
#include "NASSerializer.h"
#include "LTEUtils.h"
NASUtils::NASUtils() {
// TODO Auto-generated constructor stub
}
NASUtils::~NASUtils() {
// TODO Auto-generated destructor stub
}
NASHeader NASUtils::createHeader(unsigned char epsBearerId, unsigned char secHdrType, unsigned char protDiscr, unsigned char procTransId, unsigned char msgType) {
NASHeader hdr = NASHeader();
hdr.setEpsBearerId(epsBearerId);
hdr.setSecHdrType(secHdrType);
hdr.setProtDiscr(protDiscr);
hdr.setProcTransId(procTransId);
hdr.setMsgType(msgType);
hdr.setLength(protDiscr == ESMMessage ? NAS_ESM_HEADER_SIZE : NAS_EMM_HEADER_SIZE);
return hdr;
}
NASInfoElem NASUtils::createIE(unsigned char format, unsigned char ieType, unsigned char type, char value) {
NASInfoElem ie = NASInfoElem();
ie.setFormat(format);
ie.setIeType(ieType);
ie.setType(type);
ie.setValueArraySize(1);
ie.setValue(0, value);
return ie;
}
NASInfoElem NASUtils::createIE(unsigned char format, unsigned char ieType, unsigned char type, unsigned short length, const char *value) {
NASInfoElem ie = NASInfoElem();
ie.setFormat(format);
ie.setIeType(ieType);
ie.setType(type);
ie.setValueArraySize(length);
for (unsigned i = 0; i < length; i++)
ie.setValue(i, value[i]);
return ie;
}
//NASInfoElem NASUtils::createIE(unsigned char format, unsigned char ieType, unsigned short length) {
// NASInfoElem ie = NASInfoElem();
// ie.setFormat(format);
// ie.setIeType(ieType);
// ie.setValueArraySize(length);
// return ie;
//}
NASInfoElem NASUtils::createEPSMobileIdIE(unsigned char format, unsigned char typeOfId, char *id) {
char *epsMobileId;
unsigned short length;
if (typeOfId == IMSI_ID) {
bool odd = ((id[1] & 0xf0) == 0xf0);
length = odd ? IMSI_CODED_SIZE : IMSI_CODED_SIZE + 1;
epsMobileId = (char*)calloc(length, sizeof(char));
epsMobileId[0] = (odd ? 0x08 : 0) + typeOfId;
if (odd) {
epsMobileId[0] += ((unsigned char)id[0] << 4);
epsMobileId[1] = ((unsigned char)id[0] >> 4) + ((unsigned char)id[1] << 4);
memcpy(epsMobileId + 2, id + 2, IMSI_CODED_SIZE - 2);
} else {
unsigned j = 1;
unsigned l = 0;
unsigned k = 0;
for (unsigned i = 0; i < length; i += k % 2) {
epsMobileId[i] += (k % 2) ? ((unsigned char)(id[l] & ((j % 2) ? 0x0f : 0xf0)) >> 4) : ((unsigned char)(id[l] & ((j % 2) ? 0x0f : 0xf0)) << 4);
j++;
k++;
l += j % 2;
}
epsMobileId[l] += 0xf0;
}
}
return createIE(format, IEType4, EPSMobileId, length, epsMobileId);
}
char *NASUtils::processIE(NASInfoElem ie) {
char *value = (char*)calloc(ie.getValueArraySize(), sizeof(char));
for (unsigned i = 0; i < ie.getValueArraySize(); i++)
value[i] = ie.getValue(i);
return value;
}
unsigned NASUtils::processEPSMobileIdIE(NASInfoElem ie, char *&id) {
char *value = processIE(ie);
unsigned char typeOfId = value[0] & 0x07;
bool odd = value[0] & 0x08;
unsigned short length;
if (typeOfId == IMSI_ID) {
length = IMSI_CODED_SIZE;
id = (char*)calloc(length, sizeof(char));
if (odd) {
id[0] = ((value[0] >> 4) & 0x0f) + ((value[1] << 4) & 0xf0);
id[1] = ((value[1] >> 4) & 0x0f) + 0xf0;
memcpy(id + 2, value + 2, IMSI_CODED_SIZE - 2);
} else {
for (unsigned i = 0; i < length; i++) {
id[i] += ((value[i] >> 4) & 0x0f) + ((value[i + 1] << 4) & 0xf0);
}
}
}
return length;
}
bool NASUtils::parseAttachRequest(NASPlainMessage *msg, char *buf) {
char *p = buf;
msg->setIesArraySize(5);
NASSerializer parser = NASSerializer();
/* NAS key set identifier */
msg->setIes(0, parser.parseIE(p, IE_V, IEType1));
p += parser.skip;
/* EPS attach type */
msg->setIes(1, parser.parseIE(p, IE_V, IEType1));
p += parser.skip;
/* EPS mobile identity */
msg->setIes(2, parser.parseIE(p, IE_LV, IEType4));
p += parser.skip;
/* UE network capability */
msg->setIes(3, parser.parseIE(p, IE_LV, IEType4));
p += parser.skip;
/* ESM message container */
msg->setIes(4, parser.parseIE(p, IE_LVE, IEType6));
p += parser.skip;
buf = NASUtils().processIE(msg->getIes(4));
p = buf;
NASPlainMessage *smsg = new NASPlainMessage();
NASHeader hdr = NASSerializer().parseHeader(p);
if (!hdr.getLength()) {
EV << "NAS: Message decoding error. Dropping message.\n";
return false;
}
p += hdr.getLength();
smsg->setHdr(hdr);
if (smsg->getHdr().getMsgType() == PDNConnectivityRequest) {
smsg->setName("PDN-Connectivity-Request");
NASUtils().parsePDNConnectivityRequest(smsg, p);
msg->encapsulate(smsg);
} else {
delete smsg;
}
return true;
}
void NASUtils::parsePDNConnectivityRequest(NASPlainMessage *msg, char *buf) {
char *p = buf;
msg->setIesArraySize(2);
NASSerializer parser = NASSerializer();
/* PDN type */
msg->setIes(0, parser.parseIE(p, IE_V, IEType1));
p += parser.skip;
/* Request type */
msg->setIes(1, parser.parseIE(p, IE_V, IEType1));
p += parser.skip;
}
bool NASUtils::parseAttachAccept(NASPlainMessage *msg, char *buf) {
char *p = buf;
msg->setIesArraySize(5);
NASSerializer parser = NASSerializer();
/* EPS attach result */
msg->setIes(0, parser.parseIE(p, IE_V, IEType1));
p += parser.skip;
/* Spare half octet */
msg->setIes(1, parser.parseIE(p, IE_V, IEType1));
p += parser.skip;
/* T3412 value */
msg->setIes(2, parser.parseIE(p, IE_V, IEType3, 1));
p += parser.skip;
/* TAI list */
msg->setIes(3, parser.parseIE(p, IE_LV, IEType4));
p += parser.skip;
/* ESM message container */
msg->setIes(4, parser.parseIE(p, IE_LVE, IEType6));
p += parser.skip;
buf = NASUtils().processIE(msg->getIes(4));
p = buf;
NASPlainMessage *smsg = new NASPlainMessage();
NASHeader hdr = NASSerializer().parseHeader(p);
if (!hdr.getLength()) {
EV << "NAS: Message decoding error. Dropping message.\n";
return false;
}
p += hdr.getLength();
smsg->setHdr(hdr);
if (smsg->getHdr().getMsgType() == ActDefEPSBearerCtxtReq) {
smsg->setName("Activate-Default-Bearer-Request");
NASUtils().parseActDefBearerRequest(smsg, p);
msg->encapsulate(smsg);
} else {
delete smsg;
}
return true;
}
void NASUtils::parseActDefBearerRequest(NASPlainMessage *msg, char *buf) {
char *p = buf;
msg->setIesArraySize(3);
NASSerializer parser = NASSerializer();
/* EPS QoS */
msg->setIes(0, parser.parseIE(p, IE_LV, IEType4));
p += parser.skip;
/* APN */
msg->setIes(1, parser.parseIE(p, IE_LV, IEType4));
p += parser.skip;
/* PDN address */
msg->setIes(2, parser.parseIE(p, IE_LV, IEType4));
}
bool NASUtils::parseAttachReject(NASPlainMessage *msg, char *buf) {
char *p = buf;
msg->setIesArraySize(1);
NASSerializer parser = NASSerializer();
/* T3412 value */
msg->setIes(0, parser.parseIE(p, IE_V, IEType3, 1));
p += parser.skip;
/* ESM message container */
// msg->setIes(0, parser.parseIE(p, IE_LVE, IEType6));
// p += parser.skip;
//
// buf = NASUtils().processIE(msg->getIes(0));
// p = buf;
// NASPlainMessage *smsg = new NASPlainMessage();
// NASHeader hdr = NASSerializer().parseHeader(p);
// if (!hdr.getLength()) {
// EV << "NAS: Message decoding error. Dropping message.\n";
// return false;
// }
// p += hdr.getLength();
// smsg->setHdr(hdr);
//
// if (smsg->getHdr().getMsgType() == ActDefEPSBearerCtxtAcc) {
// smsg->setName("Activate-Default-Bearer-Request");
// NASUtils().parseActDefBearerAccept(smsg, p);
// msg->encapsulate(smsg);
// } else {
// delete smsg;
// }
return true;
}
bool NASUtils::parseAttachComplete(NASPlainMessage *msg, char *buf) {
char *p = buf;
msg->setIesArraySize(1);
NASSerializer parser = NASSerializer();
/* ESM message container */
msg->setIes(0, parser.parseIE(p, IE_LVE, IEType6));
p += parser.skip;
buf = NASUtils().processIE(msg->getIes(0));
p = buf;
NASPlainMessage *smsg = new NASPlainMessage();
NASHeader hdr = NASSerializer().parseHeader(p);
if (!hdr.getLength()) {
EV << "NAS: Message decoding error. Dropping message.\n";
return false;
}
p += hdr.getLength();
smsg->setHdr(hdr);
if (smsg->getHdr().getMsgType() == ActDefEPSBearerCtxtAcc) {
smsg->setName("Activate-Default-Bearer-Request");
NASUtils().parseActDefBearerAccept(smsg, p);
msg->encapsulate(smsg);
} else {
delete smsg;
}
return true;
}
void NASUtils::printMessage(NASPlainMessage *msg) {
NASHeader hdr = msg->getHdr();
EV << "===================================================\n";
EV << "NASMessage:\n";
if ((hdr.getMsgType() & 0xc0) == 0xc0)
EV << "EPSBearerId: " << (unsigned)hdr.getEpsBearerId() << endl;
if ((hdr.getMsgType() & 0x80) == 0x80)
EV << "SecHdrType: " << (unsigned)hdr.getSecHdrType() << endl;
EV << "ProtDiscr: " << (unsigned)hdr.getProtDiscr() << endl;
if ((hdr.getMsgType() & 0xc0) == 0xc0)
EV << "ProcTransId: " << (unsigned)hdr.getProcTransId() << endl;
EV << "MsgType: " << (unsigned)hdr.getMsgType() << endl;
for (unsigned i = 0; i < msg->getIesArraySize(); i++) {
NASInfoElem ie = msg->getIes(i);
EV << "NASInfoElem nr. " << i << ": ";
char str[ie.getValueArraySize() * 3 + 1];
int k = 0;
for (unsigned j = 0; j < ie.getValueArraySize(); j++, k += 3)
sprintf(&str[k], " %02x ", (unsigned char)ie.getValue(j));
str[ie.getValueArraySize() * 3] = '\0';
EV << str << endl;
}
EV << "===================================================\n";
}
//
// 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/.
//
#ifndef NASUTILS_H_
#define NASUTILS_H_
#include "NASMessage_m.h"
class NASUtils {
public:
NASUtils();
virtual ~NASUtils();
NASHeader createHeader(unsigned char epsBearerId, unsigned char secHdrType, unsigned char protDiscr, unsigned char procTransId, unsigned char msgType);
NASInfoElem createIE(unsigned char format, unsigned char ieType, unsigned char type, char value);
NASInfoElem createIE(unsigned char format, unsigned char ieType, unsigned char type, unsigned short length, const char *value);
NASInfoElem createEPSMobileIdIE(unsigned char format, unsigned char typeOfId, char *id);
// NASInfoElem createIE(); // for parsing usage
char *processIE(NASInfoElem ie);
unsigned processEPSMobileIdIE(NASInfoElem ie, char *&id);
bool parseAttachRequest(NASPlainMessage *msg, char *buf);
bool parseAttachAccept(NASPlainMessage *msg, char *buf);
bool parseAttachReject(NASPlainMessage *msg, char *buf);
bool parseAttachComplete(NASPlainMessage *msg, char *buf);
void parsePDNConnectivityRequest(NASPlainMessage *msg, char *buf);
void parseActDefBearerRequest(NASPlainMessage *msg, char *buf);
void parseActDefBearerAccept(NASPlainMessage *msg, char *buf) {}
void printMessage(NASPlainMessage *msg);
};
#endif /* NASUTILS_H_ */
//
// Copyright (C) 2012 Calin Cerchez
//
// 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
......@@ -32,12 +34,10 @@ GTPControl::~GTPControl() {
}
void GTPControl::initialize(int stage) {
GTP::initialize(stage);
nb->subscribe(this, NF_SUB_NEEDS_PDN);
nb->subscribe(this, NF_SUB_MODIF_TUNN);
subT = SubscriberTableAccess().get();
}
void GTPControl::processMessage(GTPMessage *msg, GTPPath *path) {
......@@ -61,7 +61,6 @@ void GTPControl::processMessage(GTPMessage *msg, GTPPath *path) {
}
void GTPControl::receiveChangeNotification(int category, const cPolymorphic *details) {
Enter_Method_Silent();
if (category == NF_SUB_NEEDS_PDN) {
EV << "GTPControl: Received NF_SUB_NEEDS_PDN notification. Processing notification.\n";
......@@ -89,8 +88,6 @@ void GTPControl::receiveChangeNotification(int category, const cPolymorphic *det
sub->setGTPProcedure(EUTRANInitAttachReq);
te->sendCreateSessionRequest();
}
// for (unsigned i = 0; i < sub->conns.size(); i++)
// te->sendCreateSessionRequest(sub->conns.at(i));
} else if (category == NF_SUB_MODIF_TUNN) {
EV << "GTPControl: Received NF_MODIF_TUNN notification. Processing notification.\n";
BearerContext *bearer = check_and_cast<BearerContext*>(details);
......@@ -99,6 +96,5 @@ void GTPControl::receiveChangeNotification(int category, const cPolymorphic *det
if (sub->getEmmEntity()->getState() != EMM_REGISTERED_N) {
s11Tunn->sendModifyBearerRequest();
}
}
}
//
// Copyright (C) 2012 Calin Cerchez
//
// 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
......@@ -20,6 +22,10 @@
#include "GatewayTable.h"
#include "GTP.h"
/*
* Class for GTP control protocol. This class inherits GTP generic module and adds
* GTP control functionality.
*/
class GTPControl : public GTP {
protected:
GatewayTable *gT;
......@@ -33,12 +39,9 @@ public:
virtual void initialize(int stage);
void processMessage(GTPMessage *msg, GTPPath *path);
/* subscriber */
// Subscriber *findSubscriberByIMSI(char *imsi) { return subT->findSubscriberByIMSI(imsi); }
// Subscriber *findSubscriberBySeqNr(unsigned seqNr) { return subT->findSubscriberBySeqNr(seqNr); }
// void push_back(Subscriber *sub) { subT->push_back(sub); }
/* notification board */
/*
* Notification methods.
*/
virtual void receiveChangeNotification(int category, const cPolymorphic *details);
};
......
//
// Copyright (C) 2012 Calin Cerchez
//
// 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
......
//
// Copyright (C) 2012 Calin Cerchez
//
// 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
......@@ -19,6 +21,10 @@
#include "GTPMessage_m.h"
#include "INETDefs.h"
/*
* Class for GTP message. This class inherits the message base class from .msg file
* and adds the vector with the GTP information elements.
*/
class GTPMessage : public GTPMessage_Base {
private:
typedef std::vector<GTPInfoElemPtr> GTPInfoElems;
......@@ -27,18 +33,42 @@ public:
GTPMessage(const char *name=NULL, int kind=0) : GTPMessage_Base(name,kind) {}
GTPMessage(const GTPMessage& other) : GTPMessage_Base(other.getName()) {operator=(other);}
virtual ~GTPMessage();
GTPMessage& operator=(const GTPMessage& other);
virtual GTPMessage *dup() const {return new GTPMessage(*this);}
/*
* Methods overridden but not used. You should use instead pushIe.
*/
virtual void setIesArraySize(unsigned int size);
virtual void setIes(unsigned int k, const GTPInfoElemPtr& ies_var);
/*
* Getter methods.
*/
virtual unsigned int getIesArraySize() const;
virtual GTPInfoElemPtr& getIes(unsigned int k);
/*
* Method for pushing GTP information element at the end of the vector.
*/
void pushIe(GTPInfoElemPtr ie) { ies.push_back(ie); }
// void insertAvp(unsigned pos, AVPPtr avp);
/*
* Method for printing the message contents. Currently it prints info
* only for the header.
*/
void print();
/*
* Method for finding a GTP IE with a given GTP IE type and instance. It returns
* NULL, if the GTP IE is not found.
*/
GTPInfoElemPtr findIe(unsigned char type, unsigned char instance);
/*
* Method for finding a range of GTP IEs with a given GTP IE type and instance.
*/
std::vector<GTPInfoElemPtr> findIes(unsigned char type, unsigned char instance);
};
......
......@@ -25,6 +25,6 @@ simple GTPUser
gates:
input udpIn;
output udpOut;
input radioIN;
output radioOUT;
input radioIn;
output radioOut;
}
\ No newline at end of file
//
// Copyright (C) 2012 Calin Cerchez
//
// 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
......@@ -104,7 +106,6 @@ GTPInfoElem *GTPUtils::createCauseIE(unsigned short length,
ie->setType(GTPV2_Cause);
ie->setInstance(instance);
ie->setValueArraySize(length);
// for (unsigned i = 0; i < length; i++) ie->setValue(i, value[i]);
ie->setValue(0, cause);
ie->setValue(1, ((pce << 2) & 0x04) | ((bce << 1) & 0x02) | (cs & 0x01));
if (length == GTPV2_CAUSE_IE_MAX_SIZE) {
......@@ -155,24 +156,6 @@ GTPInfoElem *GTPUtils::createFteidIE(unsigned char instance, unsigned teid, char
return GTPUtils().createIE(GTPV2_F_TEID, len, instance, val);
}
//GTPInfoElem *GTPUtils::createFteidIE(unsigned char instance, TunnelEndpoint *te) {
// GTPPath *path = te->getPath();
// unsigned len = path->getLocalAddr().isIPv6() ? 21 : 9;
// char *val = (char*)calloc(len, sizeof(char));
// char *p = val;
//
// *((char*)p) = (te->getPath()->getLocalAddr().isIPv6() ? 0x40 : 0x80) + path->getType();
// p += 1;
// *((unsigned*)p) = ntohl(te->getLocalId());
// p += 4;
// if (path->getLocalAddr().isIPv6()) { // not supported
// } else {
// *((unsigned*)p) = ntohl(path->getLocalAddr().get4().getInt());
// p += 4;
// }
// return GTPUtils().createIE(GTPV2_F_TEID, len, instance, val);
//}
char *GTPUtils::processIE(GTPInfoElem *ie) {
char *val = (char*)calloc(ie->getValueArraySize(), sizeof(char));
for (unsigned i = 0; i < ie->getValueArraySize(); i++)
......@@ -180,17 +163,6 @@ char *GTPUtils::processIE(GTPInfoElem *ie) {
return val;
}
//int GTPUtils::findIE(unsigned char type, unsigned char instance, GTPMessage *msg) {
// if (msg->getHeader()->getVersion() == 2) {
// for (unsigned i = 0; i < msg->getIesArraySize(); i++) {
// GTPInfoElem *ie = dynamic_cast<GTPInfoElem*>(msg->getIes(i));
// if ((ie->getType() == type) && (ie->getInstance() == instance))
// return i;
// }
// }
// return -1;
//}
IPvXAddress GTPUtils::processAddrIE(GTPInfoElem *addr) {
char *val = (char*)calloc(addr->getValueArraySize(), sizeof(char));
for (unsigned i = 0; i < addr->getValueArraySize(); i++)
......@@ -247,7 +219,8 @@ unsigned GTPUtils::getGTPv1InfoElemLen(unsigned char type) {
switch(type) {
case GTPV1_Recovery: return 1;
case GTPV1_TEIDData1: return 4;
default:;
default:
break;
}
return 0;
}
......@@ -266,32 +239,3 @@ std::vector<GTPInfoElem*> GTPUtils::processGroupedIE(GTPInfoElem *ie) {
}
return group;
}
//void GTPUtils::printGTPMessage(GTPMessage *msg) {
// EV << "===================================================\n";
// EV << "Version: " << (unsigned)msg->getHeader()->getVersion() << endl;
// EV << "Flags:\n";
// if (msg->getHeader()->getVersion() == GTP_V1) {
// GTPv1Header *hdr = dynamic_cast<GTPv1Header*>(msg->getHeader());
// EV << "\tProt. Type Flag: " << hdr->getPt() << endl;
// EV << "\tExt. Flag: " << hdr->getE() << endl;
// EV << "\tSeq. Nr. Flag: " << hdr->getS() << endl;
// EV << "\tNPDU Flag: " << hdr->getPn() << endl;
// EV << "Message Type: " << (unsigned)hdr->getType() << endl;
// EV << "TEID: " << hdr->getTeid() << endl;
// if (hdr->getE() || hdr->getE() || hdr->getS()) {
// EV << "Seq. Nr.: " << hdr->getSeqNr() << endl;
// EV << "NPDU Nr.: " << (unsigned)hdr->getNpduNr() << endl;
// EV << "Next Ext. Hdr. Type: " << (unsigned)hdr->getExtNextType() << endl;
// }
// } else if (msg->getHeader()->getVersion() == GTP_V2) {
// GTPv2Header *hdr = dynamic_cast<GTPv2Header*>(msg->getHeader());
// EV << "\tPiggyback. Flag: " << hdr->getP() << endl;
// EV << "\tTEID Flag: " << hdr->getT() << endl;
// EV << "Message Type: " << (unsigned)hdr->getType() << endl;
// if (hdr->getT())
// EV << "TEID: " << hdr->getTeid() << endl;
// EV << "Seq. Nr.: " << hdr->getSeqNr() << endl;
// }
// EV << "===================================================\n";
//}
//
// Copyright (C) 2012 Calin Cerchez
//
// 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
......@@ -21,47 +23,44 @@
#include "TunnelEndpoint.h"
#include "GTP.h"
/*
* GTP utility class. It is used for creating and processing GTP header and GTP
* information elements.
*/
class GTPUtils {
// GTPMessageTemplate createTemplate();
public:
GTPUtils();
virtual ~GTPUtils();
/*
* Methods for GTP header and GTP information element creation.
*/
GTPv2Header *createHeader(unsigned char type, bool p, bool t, unsigned int teid, unsigned int seqNr);
GTPv1Header *createHeader(unsigned char type, bool pt, bool e, bool s, bool pn, unsigned int teid, unsigned int seqNr, unsigned char npduNr, unsigned char extNextType, std::vector<GTPv1Extension> exts);
GTPInfoElem *createIE(unsigned char type, unsigned short length, unsigned char instance, char *value);
GTPInfoElem *createIE(unsigned char type, unsigned char instance, std::string value);
GTPInfoElem *createIE(unsigned char version, unsigned char type, unsigned char instance, char value);
char *processIE(GTPInfoElem *ie);
GTPInfoElem *createIntegerIE(unsigned char type, unsigned char instance, unsigned value);
GTPInfoElem *createCauseIE(unsigned short length, unsigned char instance, unsigned char cause, bool pce = false, bool bce = false, bool cs = false, unsigned char ieType = 0, unsigned char ieInstance = 0);
GTPInfoElem *createAddrIE(unsigned char type, unsigned char instance, IPvXAddress addr);
GTPInfoElem *createFteidIE(unsigned char instance, unsigned teid, char type, IPvXAddress addr);
GTPInfoElem *createGroupedIE(unsigned char type, unsigned char instance, unsigned length, std::vector<GTPInfoElem*>ies);
GTPInfoElem *createCauseIE(unsigned short length,
unsigned char instance,
unsigned char cause,
bool pce = false,
bool bce = false,
bool cs = false,
unsigned char ieType = 0,
unsigned char ieInstance = 0);
/*
* Methods for GTP header and GTP information element processing. They return the
* payload taken from the GTP information element (unsigned, integer, char etc
* values).
*/
unsigned char processCauseIE(GTPInfoElem *cause);
GTPInfoElem *createAddrIE(unsigned char type, unsigned char instance, IPvXAddress addr);
char *processIE(GTPInfoElem *ie);
IPvXAddress processAddrIE(GTPInfoElem *addr);
GTPInfoElem *createFteidIE(unsigned char instance, unsigned teid, char type, IPvXAddress addr);
// GTPInfoElem *createFteidIE(unsigned char instance, TunnelEndpoint *te);
TunnelEndpoint *processFteidIE(GTPInfoElem *fteid);
GTPInfoElem *createGroupedIE(unsigned char type, unsigned char instance, unsigned length, std::vector<GTPInfoElem*>ies);
std::vector<GTPInfoElem*> processGroupedIE(GTPInfoElem *ie);
// int findIE(unsigned char type, unsigned char instance, GTPMessage *msg);
/*
* Method for returning the length of a GTPv1 information element based on its type.
*/
unsigned getGTPv1InfoElemLen(unsigned char type);
// void printGTPMessage(GTPMessage *msg);
// GTPInfoElem *checkAndReturnCause(GTPMessage *msg, unsigned mandatoryLeft, GTPInfoElemTemplate elems[GTP_IE_TYPE_MAX][GTP_IE_INSTANCE_MAX]);
};
#endif /* GTPUTILS_H_ */
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册