Files
openbts/SGSNGGSN/Ggsn.cpp
2014-07-16 23:57:22 +02:00

631 lines
23 KiB
C++

/*
* Copyright 2011, 2014 Range Networks, Inc.
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing
* information for this specific distribution.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.
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.
*/
#include <stdint.h>
#include <poll.h>
#include "LLC.h"
#define GGSN_IMPLEMENTATION 1
#include "SgsnBase.h"
#include "Sgsn.h"
#include "Ggsn.h"
#include "miniggsn.h"
#include <GSMConfig.h>
//#include "MSInfo.h" // To dump MSInfo
#include "GPRSL3Messages.h"
#define CASENAME(x) case x: return #x;
// GSM04.08 (24.008 better) 9.5.1 describes Activate PDP Context Request Message.
// The incoming IP address is in pdp->eua.v
// GSM04.08 10.5.6.4 describes the Packed Data Protocol Address.
// If second byte (the length) is 2 and type is IP, DHCP assigns an IP address.
// We dont support anything else.
// We are just going to ignore the incoming address, and assign it one from our range.
// We are permitted to change IPv6 to use IPv4, but since we ignore it all, doesnt matter.
// GSM04.08 10.5.6.4 describes Packet Data Protocol Configuration Options.
// This is there solely to support optional PPP tunneling all the way from
// TE (Terminal Equipment) attached to the MS, through the SGSN and GGSN, and out
// to some internet endpoint elsewhere. Special support is needed both to establish
// the PPP connection and to service it, since it is its own protocol and packets
// for PPP connection types need to be passed through the GGSN.
// We will not support PPP now.
namespace SGSN {
Ggsn gGgsn;
static uint32_t mg_dns[2] = {0,0};
const char *SmCause::name(unsigned mt, bool ornull)
{
switch (mt) {
CASENAME(Operator_Determined_Barring)
CASENAME(MBMS_bearer_capabilities_insufficient_for_the_service)
CASENAME(LLC_or_SNDCP_failure)
CASENAME(Insufficient_resources)
CASENAME(Missing_or_unknown_APN)
CASENAME(Unknown_PDP_address_or_PDP_type)
CASENAME(User_authentication_failed)
CASENAME(Activation_rejected_by_GGSN_Serving_GW_or_PDN_GW)
CASENAME(Activation_rejected_unspecified)
CASENAME(Service_option_not_supported)
CASENAME(Requested_service_option_not_subscribed)
CASENAME(Service_option_temporarily_out_of_order)
CASENAME(NSAPI_already_used)
CASENAME(Regular_deactivation)
CASENAME(QoS_not_accepted)
CASENAME(Network_failure)
CASENAME(Reactivation_required)
CASENAME(Feature_not_supported)
CASENAME(Semantic_error_in_the_TFT_operation)
CASENAME(Syntactical_error_in_the_TFT_operation)
CASENAME(Unknown_PDP_context)
CASENAME(Semantic_errors_in_packet_filter)
CASENAME(Syntactical_errors_in_packet_filter)
CASENAME(PDP_context_without_TFT_already_activated)
CASENAME(Multicast_group_membership_timeout)
CASENAME(Activation_rejected_BCM_violation)
CASENAME(PDP_type_IPv4_only_allowed)
CASENAME(PDP_type_IPv6_only_allowed)
CASENAME(Single_address_bearers_only_allowed)
CASENAME(Collision_with_network_initiated_request)
CASENAME(Invalid_transaction_identifier_value)
CASENAME(Semantically_incorrect_message)
CASENAME(Invalid_mandatory_information)
CASENAME(Message_type_nonexistent_or_not_implemented)
CASENAME(Message_type_not_compatible_with_the_protocol_state)
CASENAME(Information_element_nonexistent_or_not_implemented)
CASENAME(Conditional_IE_error)
CASENAME(Message_not_compatible_with_the_protocol_state)
CASENAME(Protocol_error_unspecified)
CASENAME(APN_restriction_value_incompatible_with_active_PDP_context)
case 0:
return ornull ? 0 : "SmCause type 0";
default:
return ornull ? 0 : "SmCause type unrecognized";
}
}
static void sethighpri()
{
pthread_t me = pthread_self();
int policy; struct sched_param sp;
pthread_getschedparam(me,&policy,&sp);
SGSNLOG("service loop"<<LOGVAR(policy)<<LOGVAR2("priority",sp.sched_priority));
policy = SCHED_FIFO; // Gives this thread higher priority.
pthread_setschedparam(me,policy,&sp);
}
void *miniGgsnReadServiceLoop(void *arg)
{
Ggsn *ggsn = (Ggsn*)arg;
sethighpri();
while (ggsn->active() && !gBTS.btsShutdown()) {
struct pollfd fds[1];
fds[0].fd = tun_fd;
fds[0].events = POLLIN;
fds[0].revents = 0; // being cautious
// We time out occassionally to check if the user wants to shut the sgsn down.
if (-1 == poll(fds,1,ggsn->mStopTimeout)) {
SGSNERROR("ggsn: poll failure, errno="<<strerror(errno));
continue;
}
if (fds[0].revents & POLLIN) {
miniggsn_handle_read();
}
}
return 0;
}
void *miniGgsnWriteServiceLoop(void *arg)
{
sethighpri();
Ggsn *ggsn = (Ggsn*)arg;
while (ggsn->active() && !gBTS.btsShutdown()) {
// 8-6-2012 This interthreadqueue is clumping things up. Try taking out the timeout.
//PdpPdu *npdu = ggsn->mTxQ.read(ggsn->mStopTimeout);
PdpPdu *npdu = ggsn->mTxQ.read();
if (npdu) {
miniggsn_snd_npdu_by_mgc(npdu->mgp, npdu->mpdu.begin(), npdu->mpdu.size());
delete npdu;
}
}
return 0;
}
void addShellRequest(const char *wCmd,GmmInfo*gmm,PdpContext *pdp)
{
ShellRequest *req = new ShellRequest();
req->msrCommand = wCmd;
req->msrArg1 = gmm->mImsi.hexstr();
if (pdp && pdp->mgp) {
char ipaddr[40], nsapi[10];
ip_ntoa(pdp->mgp->mg_ip, ipaddr);
req->msrArg2 = ipaddr;
sprintf(nsapi,"%d",pdp->mNSapi);
req->msrArg3 = nsapi;
}
gGgsn.mShellQ.write(req);
}
void addShellRequest(const char *wCmd,const char *arg1)
{
ShellRequest *req = new ShellRequest();
req->msrCommand = wCmd;
req->msrArg1 = arg1;
gGgsn.mShellQ.write(req);
}
// Lurk on the mShellQ and execute a shell script to process requests found.
void *miniGgsnShellServiceLoop(void *arg)
{
Ggsn *ggsn = (Ggsn*)arg;
std::string shname = gConfig.getStr(SQL_SHELLSCRIPT);
while (ggsn->active() && !gBTS.btsShutdown()) {
ShellRequest *req = ggsn->mShellQ.read(ggsn->mStopTimeout);
if (! req) continue;
// (pat added 3-2014) Dont try to exec a shell script that does not exist; prevents a warning.
if (0 != access(shname.c_str(),R_OK)) continue;
runcmd("/bin/sh","sh",shname.c_str(), req->msrCommand.c_str(), req->msrArg1.c_str(),
req->msrArg2.c_str(),req->msrArg3.c_str());
delete req;
}
return 0;
}
// Return true on success
bool Ggsn::start()
{
if (gGgsn.mActive) { return false; }
if (!miniggsn_init()) { return false; }
gGgsn.mGgsnRecvThread.start(miniGgsnReadServiceLoop,&gGgsn);
gGgsn.mGgsnSendThread.start(miniGgsnWriteServiceLoop,&gGgsn);
if (gConfig.getStr(SQL_SHELLSCRIPT).size() > 1) {
gGgsn.mGgsnShellThread.start(miniGgsnShellServiceLoop,&gGgsn);
gGgsn.mShellThreadActive = true;
}
gGgsn.mActive = true;
//time_t now; time(&now);
//char timebuf[30];
//ctime_r(&now,timebuf);
//addShellRequest("Start",timebuf);
addShellRequest("Start","");
return true;
}
void Ggsn::stop()
{
if (!gGgsn.mActive) {return;}
gGgsn.mGgsnRecvThread.join();
gGgsn.mGgsnSendThread.join();
if (gGgsn.mShellThreadActive) {
gGgsn.mGgsnShellThread.join();
gGgsn.mShellThreadActive = false;
}
gGgsn.mActive = false;
}
// Call this to update the PCO for retransmission to the MS.
// We cannot just make up a PCO ahead of time and then send it out to
// all the MS for two reasons:
// o The incoming options have uniquifying transaction identifiers that are
// different each time, so we must modify the incoming pcoReq each time while
// carefully preserving those modifiers.
// o There are two major formats for the PCO options - see below.
static void setPco(ByteVector &resultpco, ByteVector &pcoReq)
{
if (mg_dns[0] == 0) { ip_finddns(mg_dns); }
// GSM 24.008 10.5.6.3: Procotol Configuration Options.
// These are the "negotiated" address params wrapped in PPP,
// except they are not very negotiated; we are going to cram them
// into the MS and it can accept them or die.
// The first byte is the header, followed by any number of:
// protocol id (2 octets)
// length of contents (1 octet)
// I have seen this supplied by the MS in two different ways:
// - as two separate 0x8021 requests, each with a single option request
// (Blackberry)
// - as a single 0x8021 request with two option requests for the two DNS servers.
// (Samsung phone)
resultpco.clone(pcoReq);
unsigned char *pc = resultpco.begin();
unsigned char *end = pc + resultpco.size();
__attribute__((unused)) const char *protname = "";
if (*pc++ != 0x80) {
MGERROR("SGSN: Unrecognized PCO Config Protocol: %d\n",pc[-1]);
} else while (pc < end) {
unsigned proto = (pc[0] << 8) + pc[1];
pc += 2;
unsigned ipcplen = *pc++;
if (proto == 0x8021) { // IP Control Protocol.
// IPCP looks like this:
// 1 byte: command: 1 => configure-request
// 1 byte: transaction uniquifying identifier.
// 2 bytes: total length of ipcp (even though length above was a byte)
// Followed by IPCP options, where each option is:
// 1 byte: option code
// 1 byte: total option length N (should be 6)
// N bytes: data
if (pc[0] == 1) { // command = configure-request
// pc[1] is the uniquifying identifier, leave it alone.
// pc[2]&pc[3] are another length.
// Followed by one or more 6 byte option consisting of:
// pc[4]: IPCP option code
// pc[5]: length (6)
// pc[6-9]: data
// Note: the 4 byte header length is included in the option_len
unsigned ipcp_len = pc[3]; // pc[2] better be 0.
unsigned char *op;
for (op = &pc[4]; op < pc + ipcp_len; op += op[1]) {
const char *what = "";
switch (op[0]) {
case 0x81: // primary dns.
pc[0] = 2; // IPCP command = ACK
if (op[1] < 6) {
bad_ipcp_opt_len:
MGERROR("SGSN: Invalid PCO IPCP Config Option Length: opt=0x%x len=%d\n",
op[0], op[1]);
goto next_protocol;
}
memcpy(&op[2], &mg_dns[0], 4); // addr in network order.
break;
case 0x83: // secondary dns
pc[0] = 2; // IPCP command = ACK
if (op[1] < 6) { goto bad_ipcp_opt_len; }
memcpy(&op[2], &mg_dns[mg_dns[1] ? 1 : 0], 4); // addr in network order.
break;
case 2:
what = "IP Compression Protocol"; goto bad_ipcp;
case 0x82:
what = "primary NBNS [NetBios Name Service]"; goto bad_ipcp;
case 0x84:
what = "secondary NBNS [NetBios Name Service]"; goto bad_ipcp;
default: bad_ipcp:
// It would be nice to send an SMS message that the phone is set up improperly.
MGWARN("SGSN: warning: ignoring PDP Context activation IPCP option %d %s\n",pc[4],what);
break;
}
}
}
} else if (proto == 0xc021) { // LCP:
protname = "(LCP [Link Control Protocol] for PPP)";
goto unsupported_protocol;
} else if (proto == 0xc223) { // CHAP:
protname = "(CHAP [Challenge-Handshake Authentication Protocol] for PPP)";
goto unsupported_protocol;
} else if (proto == 0xc023) { // PAP: Password authentication protocol.
protname = "(PAP [Password Authentication Protocol] for PPP)";
goto unsupported_protocol;
} else {
// If we see any of these options are non-empty, the MS may be configured to use PPP.
// It is hopeless; user must reconfigure the MS.
unsupported_protocol:
if (ipcplen) {
// 6-12: Remove this message for the 3.0 release because we get
// lots of bogus complaints about PAP.
//MGWARN("SGSN: warning: ignoring PDP Context activation sub-protocol 0x%x %s; MS may require reconfiguration.\n",proto,protname);
}
}
next_protocol:
pc += ipcplen;
}
}
static void setIpAddr(ByteVector &result,mg_con_t *mgp)
{
// This is the IP address, only IPv4 supported.
// If the MS asks for IPv6, it is supposed to accept IPv4 anyway.
result = ByteVector(6);// IPv4 address + 2 byte header.
// 3GPP 24.008 10.5.6.4
result.setByte(0,0x01); // IETF allocated address, which is all we support.
result.setByte(1,0x21); // IPv4.
// This is a special case - we cannot use setUIint32 because it converts to network order,
// but the ip address is already in network order, which is what 3GPP requires, so just copy it.
memcpy(result.begin()+2, &mgp->mg_ip, 4);
}
// TODO: We have to set the transaction identifier for the PdpContext?
//void sendPdpDeactivateAll(SgsnInfo *si, unsigned cause) //SmCause::Cause cause)
void sendPdpDeactivateAll(SgsnInfo *si, SmCause::Cause cause)
{
// TODO: what should transactionId be?
// This is a downlink command, and we are supposed to allocate a new transaction id for each one,
// but since this is the only one we ever send, maybe 0 is ok.
int transactionId = 0;
L3SmMsgDeactivatePdpContextRequest deact(transactionId,(SmCause::Cause)cause,true);
//si->getLlcEntity(LlcSapi::GPRSMM)->lleWriteHighSide(deact);
si->sgsnWriteHighSideMsg(deact);
}
//void sendSmStatus(SgsnInfo *si,SmCause::Cause cause)
//{
// L3SmMsgSmStatus smstat(cause);
// LlcDlFrame bv(1000);
// smstat.smwrite(bv);
// SGSNLOG("Sending "<<smstat.str() <<" "<<si);
// si->getLlcEntity(LlcSapi::GPRSMM)
// ->lleWriteHighSide(bv,false,"pdp context reject");
//}
static void sendPdpContextReject(SgsnInfo *si,SmCause::Cause cause,unsigned ti)
{
L3SmMsgActivatePdpContextReject pdpRej(ti,cause);
si->sgsnWriteHighSideMsg(pdpRej);
}
void sendPdpContextAccept(SgsnInfo *si, PdpContext *pdp)
{
L3SmMsgActivatePdpContextAccept pdpa(pdp->mTransactionId);
pdpa.mLlcSapi = pdp->mLlcSapi;
// On the blackberry, the qosReq is 3 bytes, but it will fail is you just return that.
// Must return the whole shebang.
SmQoS resultQoS(12); // The full 12 byte QoS works.
resultQoS.defaultPS(pdp->mRabStatus.mRateDownlink,pdp->mRabStatus.mRateUplink);
pdpa.mQoS = resultQoS;
pdpa.mRadioPriority = 2; // 2 is a medium priority. Why do we pass this to the MS at all?
setPco(pdpa.mPco,pdp->mPcoReq);
setIpAddr(pdpa.mPdpAddress,pdp->mgp);
// No Packet Flow Identifier - not implemented.
// No SM cause, unless "the network accepts the requested PDN connectivity with restrictions."
SGSNLOG("Sending "<<pdpa.str() <<" "<<si); //done by sgsnWriteHighSideMsg
// Send L3 Activate PDP Context Accept it on its way.
si->sgsnWriteHighSideMsg(pdpa);
addShellRequest("PdpActivate",si->getGmm(),pdp);
}
// TODO: All the messages below should include the phone tlli.
static void handleActivatePdpContextRequest(SgsnInfo *si, L3SmMsgActivatePdpContextRequest &pdpr)
{
unsigned ti = pdpr.mTransactionId;
const char *name = "Activate Pdp Context Request:";
// For UMTS, the MS that does not support GPRS is supposed to set the LlcSapi
// to "LLC-non-assigned" which is value 0, and then the Network is supposed to send the same one back.
// So just dont bother to validate llc sapi at all in UMTS, since we dont use it for anything.
#if RN_UMTS == 0
if (! LlcEngine::isValidDataSapi(pdpr.mLlcSapi)) {
SGSNWARN(name<<"invalid llc sapi:"<<pdpr.mLlcSapi);
sendPdpContextReject(si,SmCause::Invalid_mandatory_information,ti);
return;
}
#endif
if (pdpr.mNSapi < 5 || pdpr.mNSapi > 15) {
SGSNWARN(name<<"invalid ns sapi:"<<pdpr.mNSapi);
sendPdpContextReject(si,SmCause::Invalid_mandatory_information,ti);
return;
}
// After the BTS is power cycled, the MS may attempt to re-establish the connection by
// sending ActivatePdpContextRequest first thing. We want to force it to re-attach,
// but the Blackberry, for one, does not follow the spec on this procedure and
// generally ignores the 'implicity_detached' status message.
// Not too surprising, because unlike us, power-cycling their SGSN for testing is
// probably not that easy for the MS manufacturers.
if (!si->isRegistered()) {
sendPdpContextReject(si,SmCause::Message_not_compatible_with_the_protocol_state,ti);
// Send a GMM message too, just to be safe.
sendImplicitlyDetached(si);
return;
}
GmmInfo *gmm = si->getGmm();
assert(gmm); // if isRegistered is true then mGmmp is set by definition.
PdpContext *pdp = gmm->getPdp(pdpr.mNSapi);
bool duplicateRequest = false;
if (pdp) {
if (pdp->mTransactionId == pdpr.mTransactionId) {
// Another request for the same pdp.
duplicateRequest = true;
if (pdp->mNSapi != (int) pdpr.mNSapi) {
// TODO: We should punt at this point.
SGSNWARN(name<<"duplicate request with different ns sapi:"<<pdpr.mNSapi);
}
} else {
SGSNWARN(name<<"ns sapi already in use:"<<pdpr.mNSapi);
sendPdpContextReject(si,SmCause::NSAPI_already_used,ti);
return;
}
}
if (duplicateRequest) {
SGSNLOG("Duplicate PdpContextRequest");
} else {
// Allocate an IP address.
mg_con_t *mgp = mg_con_find_free(gmm->mPTmsi,pdpr.mNSapi);
if (mgp == NULL) {
SGSNERROR(name<<"out of ip addresses");
sendPdpContextReject(si,SmCause::Insufficient_resources,ti);
return;
}
// Okey dokey. Allocate and hook up.
//pdp = allocPdp(pdpr.mNSapi,pdpr.mLlcSapi,mgp);
//LlcEntityUserData *userdatalle = si->getLlcEntityUserData(pdpr.mLlcSapi);
//sndcp = new Sndcp(pdpr.mNSapi,pdpr.mLlcSapi,userdatalle);
pdp = new PdpContext(gmm,mgp,pdpr.mNSapi,pdpr.mLlcSapi);
gmm->connectPdp(pdp,mgp);
//mgp->mg_pdp = pdp;
//sndcp->setPdp(pdp);
#if RN_UMTS
// For UMTS the PDP context creation is two-part.
// At this point we must allocate the RB [Radio Bearer] for the UE
// and we must wait for the acknowledgement message from the UE
// before we can send the final ActivatePdpContextAccept message.
// Like this:
// L3 ActivatePdpContextRequest, NSAPI=n (n=5..15)
// MS ---------------------------------> Network
// RRC RadioBearerSetup, RbId=n
// MS <--------------------------------- Network
// RRC RadioBearerSetupComplete
// MS ---------------------------------> Network
// L3 ActivatePdpContextAccept NSAPI=n
// MS <--------------------------------- Network
pdp->mRabStatus = SgsnAdapter::allocateRabForPdp(si->mMsHandle,pdpr.mNSapi,pdpr.mQoS);
switch (pdp->mRabStatus.mStatus) {
case RabStatus::RabFailure:
SGSNERROR(name<<"Rab Allocation Failure:"<<SmCause::name(pdp->mRabStatus.mFailCode));
sendPdpContextReject(si,pdp->mRabStatus.mFailCode,ti);
return;
case RabStatus::RabPending:
pdp->mUmtsStatePending = true;
pdp->mPendingPdpr = pdpr;
return;
case RabStatus::RabAllocated:
// The Rab was allocated previously by this UE.
// Fall through to resend the accept message.
break;
default: assert(0);
}
#else
// It is gprs. The link is already allocated.
// We ignore the QoS request; what a joke - it barely goes low enough to specify the GPRS bandwidth.
// For now, just use the base throughput of the GPRS link which is 2.5KBytes/sec less overhead.
// TODO: set the uplink/downlink rates from the multi-slot class of the MS.
pdp->mRabStatus.mStatus = RabStatus::RabAllocated;
pdp->mRabStatus.mRateUplink = pdp->mRabStatus.mRateDownlink = 2;
#endif
}
// This must be set each time, because it has uniquifying ids in it:
pdp->update(pdpr);
sendPdpContextAccept(si,pdp);
/*****
// Create the accept message. 3GPP 24.008 9.5.2.
//L3SmMsgActivatePdpContextAccept pdpa(pdpr.mTransactionId);
L3SmMsgActivatePdpContextAccept pdpa(pdp->mTransactionId);
// Note: we send back the llc sapi was sent to us, even if it is invalid.
pdpa.mLlcSapi = pdpr.mLlcSapi;
// Using the qos params from the sender did not work.
// Send our own default qos params:
setQoS(pdpa.mQoS,pdpr.mQoS);
pdpa.mRadioPriority = 2; // 2 is a medium priority. Why do we pass this to the MS at all?
setPco(pdpa.mPco,pdpr.mPco);
setIpAddr(pdpa.mPdpAddress,pdp->mgp);
// No Packet Flow Identifier - not implemented.
// No SM cause, unless "the network accepts the requested PDN connectivity with restrictions."
SGSNLOG("Sending "<<pdpa.str() <<" "<<si);
// Send L3 Activate PDP Context Accept it on its way.
si->sgsnWriteHighSideMsg(pdpa);
****/
}
void handleDeactivatePdpContextRequest(SgsnInfo *si, L3SmMsgDeactivatePdpContextRequest &deact)
{
unsigned nsapi;
unsigned nsapiMask = 0; // Mask of nsapi that were freed.
if (deact.mTearDownIndicator) {
nsapiMask = si->freePdpAll(false);
} else {
// Look for the pdp with this transaction identifier.
bool found = false;
for (nsapi = 0; nsapi < 16; nsapi++) { // 0-4 are unused, but be safe.
PdpContext *pdp;
if ((pdp = si->getPdp(nsapi))) {
if (pdp->mTransactionId == deact.mTransactionId) {
addShellRequest("PdpDeactivate",si->getGmm(),pdp);
si->freePdp(nsapi);
nsapiMask = 1<<nsapi;
found = true;
break;
}
}
}
if (!found) {
SGSNWARN("PdpContextDeactivate: pdp context not found for ti="<<deact.mTransactionId);
// and send what??
}
}
// Send L3 Activate PDP Context Accept on its way.
L3SmMsgDeactivatePdpContextAccept deactaccept(deact.mTransactionId);
//gmmlle->lleWriteHighSide(deactaccept);
si->sgsnWriteHighSideMsg(deactaccept);
// Deactivate the RABs. Only does something in UMTS, a no-op in GPRS.
// 23.060 9.3.4.1 shows the RABs being deactivated after sending
// the DeactivatePdpContextAccept message, so we will comply,
// although it probably does not matter. These are sent in acknowledged mode
// so it is conceivable that they will not arrive at the UE in order.
if (nsapiMask) { si->deactivateRabs(nsapiMask); }
}
// The gmmlle is the lle of the GMM entity, the one to which we should return a message.
void Ggsn::handleL3SmMsg(SgsnInfo *si,L3GprsFrame &frame1)
{
L3SmFrame frame(frame1);
unsigned mt = frame.getMsgType(); // message type
//SGSNLOG("CRACKING SM MSG TYPE "<<mt);
switch (mt) {
case L3SmMsg::ActivatePDPContextRequest: {
L3SmMsgActivatePdpContextRequest pdpr(frame);
SGSNLOG("Received "<<pdpr.str() <<si);
handleActivatePdpContextRequest(si,pdpr);
break;
}
case L3SmMsg::SMStatus: {
L3SmMsgSmStatus stmsg(frame);
SGSNLOG("Received SmStatus: "<<stmsg.str()<<si);
break;
}
//case L3SmMsg::ActivatePDPContextAccept:
//case L3SmMsg::ActivatePDPContextReject:
//case RequestPDPContextActivation:
//case RequestPDPContextActivationReject:
case L3SmMsg::DeactivatePDPContextRequest: {
//SGSNLOG("Incoming Deactivate pdp, frame="<<frame<< " bv="<<(ByteVector)frame);
L3SmMsgDeactivatePdpContextRequest deact(frame);
SGSNLOG("Received DeactivatePdpContextRequest: "<<deact.str());
handleDeactivatePdpContextRequest(si,deact);
break;
}
//DeactivatePDPContextAccept:
//ModifyPDPContextRequest = 0x48, // network to MS direction.
//ModifyPDPContextAccept = 0x49, // MS to netowrk direction.
//ModifyPDPContextRequestMS = 0x4a, // MS to network direction.
//ModifyPDPContextAcceptMS = 0x4b, // network to MS direction.
//ModifyPDPContextReject = 0x4c,
//ActivateSecondaryPDPContextRequest = 0x4d,
//ActivateSecondaryPDPContextAccept = 0x4e,
//ActivateSecondaryPDPContextReject = 0x4f,
// From GSM 24.008:
//ActivateMBMSContextRequest = 0x56,
//ActivateMBMSContextAccept = 0x57,
//ActivateMBMSContextReject = 0x58,
//RequestMBMSContextActivation = 0x59,
//RequestMBMSContextActivationReject = 0x5a,
//RequestSecondaryPDPContextActivation = 0x5b,
//RequestSecondaryPDPContextActivationReject = 0x5c,
//Notification = 0x5d,
default:
SGSNWARN("Ignoring GPRS SM message type "<<mt<<" " <<L3SmMsg::name(mt));
break;
}
}
}; // namespace