Example #1
0
void PDCHL1Downlink::bugFixIdleFrame()
{
	// DEBUG: We are only using this function to fix this problem for now.
	if (gFixIdleFrame) {
		// For this debug purpose, the mssage is sent on the next frame
		// TODO: debug purpose only! This only works for one channel!
		//Time tnext(gBSNNext.FN());
		//gBTS.clock().wait(tnext);
	}

	// Did we make it in time?
	{
	Time tnow = gBTS.time();
	int fn = tnow.FN();
	int mfn = (fn / 13);			// how many 13-multiframes
	int rem = (fn - (mfn*13));	// how many blocks within the last multiframe.
	int tbsn = mfn * 3 + ((rem==12) ? 2 : (rem/4));
	GPRSLOG(2) <<"idleframe"<<LOGVAR(fn)<<LOGVAR(tbsn)<<LOGVAR(rem);
	}

	/***
	if (mchIdleFrame.size() == 0) {
		RLCMsgPacketDownlinkDummyControlBlock *dummymsg = new RLCMsgPacketDownlinkDummyControlBlock();
		mchIdleFrame.set(BitVector(RLCBlockSizeInBits[ChannelCodingCS1]));
		dummymsg->write(mchIdleFrame);
		delete dummymsg;
	}
	send1Frame(mchIdleFrame,ChannelCodingCS1,true);
	***/
}
Example #2
0
string SipMessage::text(bool verbose) const
{
	std::ostringstream ss;
	ss << "SipMessage(";
	{ int code = smGetCode(); ss <<LOGVAR(code); }
	if (!msmReqMethod.empty()) ss <<LOGVAR2("ReqMethod",msmReqMethod);
	if (!msmReason.empty()) ss <<LOGVAR2("reason",msmReason);
	if (!msmCSeqMethod.empty()) ss<<" CSeq="<<msmCSeqNum<< " "<<msmCSeqMethod;
	if (!msmCallId.empty()) ss <<LOGVAR2("callid",msmCallId);
	if (!msmReqUri.empty()) ss << LOGVAR2("ReqUri",msmReqUri);
	{ string To = msmTo.value(); if (!To.empty()) ss << LOGVAR(To); }
	{ string From = msmFrom.value(); if (!From.empty()) ss<<LOGVAR(From); }
	if (!msmVias.empty()) ss <<LOGVAR2("Vias",msmVias);
	if (!msmRoutes.empty()) ss <<LOGVAR2("Routes",msmRoutes);
	if (!msmRecordRoutes.empty()) ss <<LOGVAR2("RecordRoutes",msmRecordRoutes);
	if (!msmContactValue.empty()) ss <<LOGVAR2("Contact",msmContactValue);
	//list<SipBody> msmBodies;
	if (!msmContentType.empty()) ss<<LOGVAR2("ContentType",msmContentType);
	if (!msmBody.empty()) ss<<LOGVAR2("Body",msmBody);
	//if (!msmAuthenticateValue.empty()) ss<<LOGVARM(msmAuthenticateValue);
	if (!msmAuthorizationValue.empty()) ss<<LOGVARM(msmAuthorizationValue);
	for (SipParamList::const_iterator it = msmHeaders.begin(); it != msmHeaders.end(); it++) {
		ss <<" header "<<it->mName <<"="<<it->mValue;
	}

	if (verbose) { ss << LOGVARM(msmContent); } else { ss << LOGVAR2("firstLine",smGetFirstLine()); }
	ss << ")";
	return ss.str();
}
Example #3
0
string SipMessage::smGetInviteImsi()
{
	// Get request username (IMSI) from assuming this is the invite message.
	string username = smUriUsername();
	LOG(DEBUG) <<LOGVAR(username) <<LOGVAR(extractIMSI(sipSkipPrefix1(username.c_str())));
	return string(extractIMSI(sipSkipPrefix1(username.c_str())));
}
Example #4
0
// The result is 3-state (LCH, !LCH and deleteMe==true, !LCH && deleteMe==false.)
// If it is a TCH or SDCCH return an allocated channel, or NULL if not possible,
// in which case the handset may ultimately be sent an immediate assignment reject.
// On return, if deleteMe, the caller will delete the rach.
static L2LogicalChannel *preallocateChForRach(RachInfo *rach, bool *deleteMe)
{
	*deleteMe = false;

	Time now = gBTS.time();
	int age = now - rach->mWhen;	// The result is number of frames and could be negative.
	if (age>sMaxAge) {
		LOG(WARNING) << "ignoring RACH burst with age " << age;
		*deleteMe = true;
		return NULL;
	}

	L2LogicalChannel *LCH = NULL;
	ChannelType chtype = decodeChannelNeeded(rach->mRA);
	if (chtype == PSingleBlock1PhaseType || chtype == PSingleBlock2PhaseType) {
		return NULL;	// this routine does nothing for this.
	} else if (chtype == TCHFType) {
		LCH = gBTS.getTCH();
	} else if (chtype == SDCCHType) {
		LCH = gBTS.getSDCCH();
	} else {
		LOG(NOTICE) << "RACH burst for unsupported service RA=" << rach->mRA;
		// (pat) 4-2014: Stop allocating channels for this.  We get a lot of false RACHes so lets ignore those with unrecognized RA.
		// LCH = gBTS.getSDCCH();
		*deleteMe = true;
		return NULL;
	}

	if (!LCH) {
		LOG(DEBUG) << "No channels availablable, RACH discarded";
		*deleteMe = true;
		return NULL;
	}

	int initialTA = rach->initialTA();
	assert(initialTA >= 0 && initialTA <= 62);	// enforced by AccessGrantResponder.
	LCH->l1InitPhy(rach->RSSI(),initialTA,gBTS.clock().systime(rach->mWhen.FN()));
	LCH->lcstart();
	rach->mChan = LCH;
	Time sacchStart = LCH->getSACCH()->getNextWriteTime();
	// There is a race whether the thread that runs SACCH can run before sacchStart time, and if not
	// the SACCH will not be transmitted at this time.
	// Therefore, if sacchStart time is close, add a whole sacch frame, 104 frames == 480ms.
	now = gBTS.time();	// Must update this because getTCH blocked.
	int diff = sacchStart - now;	// Returns number of 4.8ms frames.
	if (diff <  26) {	// very conservative.
		sacchStart += 104;
	}
	if (sacchStart - now < 0) {
		// Should never happen.
		sacchStart = now + 104;
	}
	rach->mReadyTime = sacchStart;
	LOG(DEBUG) <<LOGVAR(sacchStart)<<LOGVAR(now)<<LOGVAR(diff);
	return LCH;
}
Example #5
0
string SipMessage::smUriUsername()
{
	string result = SipUri(msmReqUri).uriUsername();
	LOG(DEBUG) <<LOGVAR(msmReqUri) <<LOGVAR(msmTo.value()) <<LOGVAR(result);
	return result;
	//SipUri uri; uri.uriParse(msmReqUri);
	//string username = uri.username();
	//LOG(DEBUG) << LOGVAR(msmReqUri) <<LOGVAR(username);
	//return username;
}
Example #6
0
void startRegister(TranEntryId tid, const FullMobileId &msid, const string rand, const string sres, L3LogicalChannel *chan) 		// msid is imsi and/or tmsi
{
	LOG(DEBUG) <<LOGVAR(msid)<<LOGVAR(rand)<<LOGVAR(sres);
	// Kinda dumb to fish out the branch from the request, but its ok.
	SipDialog *registrar = getRegistrar();
	SipMessage *request = registrar->makeRegisterMsg(SIPDTRegister,chan,rand,msid,sres.c_str());
	SipRegisterTU *reg = new SipRegisterTU(SipRegisterTU::KindRegister,registrar,tid,request);
	delete request;		// sctInitRegisterTransaction made a copy.  Kind of wasteful.
	reg->sctStart();
}
Example #7
0
void SipTransaction::sendAuthOKMessage(SipMessage *sipmsg)
{
	devassert(mstTranId);
	// The tran id is 0 for unregister messages.  If one of those gets this far it is a bug.
	if (! mstTranId) { return; }

	string imsi = sipmsg->msmTo.uriUsername(); // The To: and From: have the same value for a REGISTER message.
	// Validate the imsi:
	if (imsi.empty()) {
		LOG(ERR) << "can't find imsi to store kc";
		sendAuthFailMessage(400,"","");
		return;
	}
	if (0 == strncasecmp(imsi.c_str(),"imsi",4)) {
		// happiness
	} else if (0 == strncasecmp(imsi.c_str(),"tmsi",4)) {
		// TODO: In future the user name could be a TMSI.
		LOG(ERR) << "SIP REGISTER message with TMSI not supported, userid="<<imsi;
		sendAuthFailMessage(400,"","");
		return;
	} else {
		LOG(ERR) << "SIP REGISTER message with invalid IMSI:"<<imsi<<" Message:"<<sipmsg->msmContent;
		sendAuthFailMessage(400,"","");
		return;
	}

	DialogAuthMessage *dmsg = new DialogAuthMessage(mstTranId, DialogState::dialogActive,200);
	dmsg->dmPAssociatedUri = sipmsg->msmHeaders.paramFind("P-Associated-URI");	// case doesnt matter
	dmsg->dmPAssertedIdentity = sipmsg->msmHeaders.paramFind("P-Asserted-Identity");

	string authinfo = sipmsg->msmHeaders.paramFind("Authentication-Info");
	if (! authinfo.empty()) {
		SipParamList params;
		parseToParams(authinfo, params);
		dmsg->dmKc = params.paramFind("cnonce"); // This is the way SR passes the Kc.
	} else {
		// There will not be a cnonce if the Registrar does not know it.  Dont worry about it.
		//LOG(INFO) << "No Authenticate-Info header in SIP REGISTER response:"<<sipmsg->msmContent;
	}

	if (dmsg->dmKc.empty()) {
		dmsg->dmKc = sipmsg->msmHeaders.paramFind("P-GSM-Kc"); // This is the way Yate passes the Kc.
	}

	WATCHF("CNONCE: imsi=%s Kc=%s\n",imsi.c_str(),dmsg->dmKc.c_str());
	if (! dmsg->dmKc.empty()) {
		LOG(DEBUG) << "Storing Kc:"<<LOGVAR(imsi)<<LOGVAR(dmsg->dmKc.size());	// We dont put Kc itself in the log.
		//gTMSITable.putKc(imsi.c_str()+4, kc, pAssociatedUri, pAssertedIdentity);
	} else {
		LOG(NOTICE) << "No Kc in SIP REGISTER response:"<<sipmsg->msmContent;
	}

	//NewTransactionTable_ttAddMessage(mstTranId,dmsg);
	SipCallbacks::ttAddMessage(mstTranId,dmsg);
}
Example #8
0
void L3SupServFacilityIE::text(ostream& os) const
{
	char rawdata[2*255+1+1];		// Add 1 extra for luck.
	unsigned len = lengthV();
	const unsigned char *components = peData();
	for (unsigned i = 0; i < len; i++) {
		sprintf(&rawdata[2*i],"%02x",components[i]);
	}
	string ussd = Control::ssMap2Ussd(components,len);
	os <<"SupServFacilityIE(size=" <<len <<" components:" <<LOGVAR(rawdata) <<LOGVAR(ussd)<<")";
}
Example #9
0
// (pat) This is started when SACCH is opened, and runs forever.
// The SACCHLogicalChannel are created by the SDCCHLogicalChannel and TCHFACCHLogicalChannel constructors.
void *SACCHLogicalChannel::SACCHServiceLoop(SACCHLogicalChannel* sacch)
{
	WATCHINFO("Starting SACCHServiceLoop for "<<sacch);
	unsigned count = 0;
	while (!gBTS.btsShutdown()) {
		//if (gBTS.time().FN() % 104 == 0) { OBJLOG(DEBUG) <<LOGVAR(l1active()) <<LOGVAR(recyclable()); }

		// Throttle back if not active.
		// This is equivalent to testing if the L2LAPDm is in 'null' state as defined in GSM 4.06.
		// In null state we send dummy frames; in L2LAPDm idle state we send L2 idle frames.
		// The dummy frame is sent down to the transceiver when L2LAPDm is closed.
		if (! sacch->l1active()) {
			// pat 5-2013: Vastly reducing the delays here and in L2LAPDm to try to reduce
			// random failures of handover and channel reassignment from SDCCH to TCHF.
			// Update: The further this sleep is reduced, the more reliable handover becomes.
			// I left it at 4 for a while but handover still failed sometimes.
			//sleepFrames(51);
#if USE_SEMAPHORE
			sleepFrames(51);	// In case the semaphore does not work.
			// (pat) Update: Getting rid of the sleep entirely.  We will use a semaphore instead.
			// Note that the semaphore call may return on signal, which is ok here.
			int sval, semstat= sem_getvalue(&mOpenSignal,&sval);
			//cout << descriptiveString() << " WAIT " <<sem_getvalue(&mOpenSignal,&sval) <<LOGVAR(sval) <<endl;
			LOG(DEBUG) << descriptiveString() << " SEM_WAIT " <<LOGVAR(semstat) <<LOGVAR(sval);
			sem_wait(&mOpenSignal);
			// sem_post sem_overview
			semstat= sem_getvalue(&mOpenSignal,&sval);
			//cout << descriptiveString() << " AFTER " <<LOGVAR(semstat) <<LOGVAR(sval) <<endl;
			LOG(DEBUG) << descriptiveString() << " SEM_AFTER " <<sem_getvalue(&mOpenSignal,&sval) <<LOGVAR(sval);
#else
			// (pat 3-2014) Changing this sleepFrames(51) to sleepFrames(2) had an enormous impact
			// on idle cpu utilization, from 11.2% to 8.5% with a C-5 beacon, ie, with only 4 SACCH running.
			// TODO: Can use fewer CPU cycles by using something like waitToSend to sleep until the next SACCH transmission time.
			sleepFrames(1);
#endif
			// A clever way to avoid the sleep above would be to wait for ESTABLISH primitive.
			// (But which do you wait on - the tx or the rx queue?
			continue;	// paranoid, check again.
		}

		// (pat 4-2014) Added to detect RR failure.  This is needed because a Layer3 MMContext is not allocated
		// until the first L3 message arrives.  If the channel fails without sending an L3 message we would never
		// notice unless we are watching these RR level timers.
		// Close the host channel, which will also close this SACCH.
		sacch->serviceSACCH(count);
	}
	//sacch->mSacchRunning = false;		dont think we would restart this one; would alloc a new one.
	return NULL;
}
Example #10
0
void PDCHL1Downlink::mchResync()
{
	// If the encoder's clock is far from the current BTS clock,
	// get it caught up to something reasonable.
	Time now = gBTS.time();
	int32_t delta = mchNextWriteTime-now;
	GPRSLOG(8) << "PDCHL1Downlink" <<LOGVAR(mchNextWriteTime)
			<<LOGVAR(now)<< LOGVAR(delta);
	if ((delta<0) || (delta>(51*26))) {
		mchNextWriteTime = now;
		//mchNextWriteTime.TN(now.TN());	// unneeded?
		mchNextWriteTime.rollForward(mchMapping.frameMapping(mchTotalBursts),mchMapping.repeatLength());
		GPRSLOG(2) <<"PDCHL1Downlink RESYNC" << LOGVAR(mchNextWriteTime) << LOGVAR(now);
	}
}
Example #11
0
void PDCHL1FEC::mchStart() {
	getRadio()->setSlot(TN(),Transceiver::IGPRS);
	// Load up the GPRS filler idle burst tables in the transceiver.
	// We could use any consecutive bsn, but lets use ones around the current time
	// just to make sure they get through in case someone is triaging somewhere.
	// Sending all 12 blocks is 2x overkill because the modulus in Transceiver::setModulus
	// for type IGPRS is set the same as type I which is only 26, not 52.
	RLCBSN_t bsn = FrameNumber2BSN(gBTS.time().FN()) + 1;
	for (int i = 0; i < 12; i++, bsn = bsn + 1) {
		GPRSLOG(1) <<"sendIdleFrame"<<LOGVAR2("TN",TN())<<LOGVAR(bsn)<<LOGVAR(i);
		mchDownlink->sendIdleFrame(bsn);
	}
	mchOldFec->setGPRS(true,this);
	debug_test();
}
Example #12
0
// (pat 9-2014) Print out peering messages.  We triage the messages depending on the log level.
// INFO level - Handover messages only.
// DEBUG level - all messages.
static void logMessage(const char*sendOrRecv, const struct sockaddr_in* peer, const char *message)
{
	const char *arg1 = getPeeringMsgArg1(message);
	if (0 == strncmp(arg1,"HANDOVER",8)) {
		LOG(INFO) << "Peering "<<sendOrRecv <<LOGVAR2("peer",sockaddr2string(peer,true)) <<LOGVAR(message);
		// We used to watch everything except REQ NEI messages: if (strncmp(message,"REQ NEI",7))
		const char *eol = strchr(message,'\n');
		WATCHLEVEL(INFO," Peering "<<sendOrRecv <<LOGVAR2("peer",sockaddr2string(peer,true))
				<<LOGVAR2("message",string(message,eol?eol-message:strlen(message))));	// first line of message; they used to be long.
	} else {
		// At DEBUG level log all messages.
		LOG(DEBUG) << "Peering "<<sendOrRecv<<LOGVAR2("peer",sockaddr2string(peer,true)) <<LOGVAR(message);
	}

}
Example #13
0
// Return true on success.
bool MTSMSMachine::createRPData(RPData &rp_data)
{
	// TODO: Read MIME Type from smqueue!!
	const char *contentType = tran()->mContentType.c_str();
	PROCLOG(DEBUG)<<LOGVAR(contentType)<<LOGVAR(tran()->mMessage);
	if (strncmp(contentType,"text/plain",10)==0) {
		TLAddress tlcalling = TLAddress(tran()->calling().digits());
		TLUserData tlmessage = TLUserData(tran()->mMessage.c_str());
		PROCLOG(DEBUG)<<LOGVAR(tlcalling)<<LOGVAR(tlmessage);
		rp_data = RPData(this->mRpduRef,
			RPAddress(gConfig.getStr("SMS.FakeSrcSMSC").c_str()),
			TLDeliver(tlcalling,tlmessage,0));
	} else if (strncmp(contentType,"application/vnd.3gpp.sms",24)==0) {
		BitVector2 RPDUbits(strlen(tran()->mMessage.c_str())*4);
		if (!RPDUbits.unhex(tran()->mMessage.c_str())) {
			LOG(WARNING) << "Message is zero length which is valid";
			// This is valid continue
			return true;
		}

		try { // I suspect this is here to catch the above FIXED crash when string is zero length
			RLFrame RPDU(RPDUbits);
			LOG(DEBUG) << "SMS RPDU: " << RPDU;

			rp_data.parse(RPDU);
			LOG(DEBUG) << "SMS RP-DATA " << rp_data;
		}
		catch (SMSReadError) {
			LOG(WARNING) << "SMS parsing failed (above L3)";
			// Cause 95, "semantically incorrect message".
			//LCH->l2sendf(CPData(L3TI,RPError(95,this->mRpduRef)),3); if you ever use this, it should call l3sendSms
			return false;
		}
		catch (GSM::L3ReadError) {
			LOG(WARNING) << "SMS parsing failed (in L3)";
			// TODO:: send error back to the phone
			return false;
		}
		catch (...) {
			LOG(ERR) << "Unexpected throw";	// cryptic, but should never happen.
			return false;
		}
	} else {
		LOG(WARNING) << "Unsupported content type (in incoming SIP MESSAGE) -- type: " << contentType;
		return false;
	}
	return true;
}
Example #14
0
L3Frame * L2LogicalChannel::l2recv(unsigned timeout_ms)
{
	LOG(DEBUG);
	L3Frame *result = mL3Out.read(timeout_ms);
	if (result) WATCHINFO("l2recv " << this <<LOGVAR2("sap",result->getSAPI()) <<LOGVAR(result));
	return result;
}
Example #15
0
void PeerInterface::process(const struct sockaddr_in* peer, const char* message)
{
	logMessage("receive",peer,message);

	// neighbor message?
	if (strncmp(message+3," NEIGHBOR_PARAMS",16)==0)
		return processNeighborParams(peer,message);

	// must be handover related
	string peerString = sockaddr2string(peer, true);
	LOG(INFO) << "received from"<<LOGVAR2("peer",peerString) <<LOGVAR(message);

	// Initial inbound handover request?
	if (strncmp(message,"REQ HANDOVER ",13)==0)
		return processHandoverRequest(peer,message);

	// Handover response? ("Handover Accept" in the ladder.)
	if (strncmp(message,"RSP HANDOVER ",13)==0)
		return processHandoverResponse(peer,message);

	// IND HANDOVER_COMPLETE
	if (strncmp(message,"IND HANDOVER_COMPLETE ", 22)==0)
		return processHandoverComplete(peer,message);

	// IND HANDOVER_FAILURE
	if (strncmp(message,"IND HANDOVER_FAILURE ", 21)==0)
		return processHandoverFailure(peer,message);

	// Other handover messages go into the FIFO map.
	// (pat) It is an ACK message, and we need to queue it because the 'senduntilack' is running in a different thread.
	// FIXME -- We need something here to spot malformed messages.
	unsigned transactionID;
	sscanf(message, "%*s %*s %u", &transactionID);
	mFIFOMap.writeFIFO(transactionID,message);
}
Example #16
0
void L2SAPMux::sapWriteFromL1(const L2Frame& frame)
{
	OBJLOG(DEBUG) << frame;
	unsigned sap;

	// (pat) Add switch to validate upstream primitives.  The upstream only generates a few primitives;
	// the rest are created in L2LAPDm.
	switch (frame.primitive()) {
		case L2_DATA:
			sap = frame.SAPI();	
			assert(sap == SAPI0 || sap == SAPI3);
			if (mL2[sap]) {
				mL2[sap]->l2dlWriteLowSide(frame);
			} else {
				LOG(WARNING) << "received DATA for unsupported"<<LOGVAR(sap);
			}
			return;
		case PH_CONNECT:
			// All this does is fully reset LAPDm; copy it out to every SAP.
			for (int s = 0; s <= 3; s++) {
				if (mL2[s]) mL2[s]->l2dlWriteLowSide(frame);	// Note: the frame may have the wrong SAP in it, but LAPDm doesnt care.
			}
			return;
		default:
			// If you get this assertion, make SURE you know what will happen upstream to that primitive.
			devassert(0);
			return;		// make g++ happy.
	}
}
Example #17
0
// It is hardly worth the effort to make a transaction for REGISTER, which occurs outside a dialog
// and has only one reply, but we need to know when to destroy it.
// Note: The registrar may return messages, which we must ignore for the Unregister case since there is no transaction to receive them.
void SipRegisterTU::TUWriteHighSideV(SipMessage *sipmsg)
{
	int code = sipmsg->msmCode;
	static const char *pRejectCauseHeader = "P-GSM-Reject-Cause";
	static const char *whatami = stKind == KindRegister ? "SIP Register " : "SIP UnRegister ";
	LOG(DEBUG) <<LOGVAR(code);
	if (code == 0) {
		// A register transaction does not receive any requests.
		LOG(ERR) << whatami <<"received unexpected message:"<<sipmsg;
		stDestroyV();
	} else if (code == 401) {
		//setDialogState(Fail,sipmsg);
		LOG(INFO) <<whatami <<"received:"<<sipmsg;
		if (stKind == KindRegister) {
			sendAuthFailMessage(code,sipmsg->smGetRand401(),sipmsg->msmHeaders.paramFind(pRejectCauseHeader));
		}
		setTransactionState(stCompleted);
	} else if (code == 200) {
		// (pat) We can no longer stash Kc directly in the TMSI table because the entry is not created until the MS is validated.
		if (stKind == KindRegister) {
			sendAuthOKMessage(sipmsg);
		}
	} else switch ((code/100) * 100) {
		case 100: return;	// we dont care.
		case 200: LOG(ERR) <<whatami<<"received invalid code:"<<code <<" in message:"<<sipmsg;	// Code in the range 201-299 is allegedly impossible.
		default:
			if (stKind == KindRegister) {
				sendAuthFailMessage(code,"",sipmsg->msmHeaders.paramFind(pRejectCauseHeader));
			}
			return;
	}
}
Example #18
0
// Simplified version for public release
bool CCCHLogicalChannel::processPages()
{
	while (NewPagingEntry *npe1 = gPagingQ.mPageQ.readNoBlock()) {
		LOG(DEBUG)<<LOGVAR(npe1);
		if (npe1->mGprsClient) {	// Is it a GPRS page?
			// Add 51 to the frame time because the message because the MS may be on the other 51-multiframe.
			Time future(mCcchNextWriteTime + 52);
			if (! sendGprsCcchMessage(npe1,future)) {
				delete npe1;	// In the incredibly unlikely event that the above failed, just give up.
				continue;
			}
		} else {
			const L3MobileIdentity& id1 = npe1->getMobileId();
			ChannelType type1 = npe1->getGsmChanType();
			L3PagingRequestType1 page1(id1,type1);
			L2LogicalChannelBase::l2sendm(page1,L3_UNIT_DATA);
		}
		if (++npe1->mSendCount < 2) {	// Send each page twice.
			gPagingQ.mPageQ.write_front(npe1);	// Put it back for resend in the next multiframe.
		} else {
			delete npe1;
		}
		return true;
	}
	return false;	// CCCH unused.
}
Example #19
0
bool SipClientTrLayer::TLWriteHighSideV(SipMessage *sipmsg)
{
	int code = sipmsg->smGetCode();
	LOG(DEBUG) <<LOGVAR(mstState) <<LOGVAR(code);
	// This is overly verbose to exactly match the state machine described in RFC3261.
	switch (mstState) {
	case stInitializing:
		// Someone sent us a reply before we sent the outgoing message?
		LOG(ERR) << "SIP Message received on uninitialized client transaction."<<LOGVAR(sipmsg) <<this;
		return false;
	case stCallingOrTrying:
	case stProceeding:
		switch ((code / 100) * 100) {
		case 100:
			mstState = stProceeding;
			TUWriteHighSideV(sipmsg);
			return true;
		default:
			mstState = stCompleted;
			TUWriteHighSideV(sipmsg);
			if (stIsInvite()) {
				mstState = stTerminated;
				if (code >= 300) { mstDialog->MOCSendACK(); }
				else { stDestroyV(); return true; } // The TU is responssible for sending the ACK, after connection setup.
			}
			if (stIsReliableTransport()) { stDestroyV(); return true; } else { mTimerDK.set(32*1000); }
			return true;
		}
	case stCompleted:
		switch ((code / 100) * 100) {
		case 100:
		case 200:
			return false;	// suppress duplicate messages.
		default:
			if (stIsInvite()) { mstDialog->MOCSendACK(); }
			return false;	// suppress duplicate messages.
		}
	case stTerminated:
		// Now what?
		LOG(ERR) << "SIP Message received on terminated client transaction."<<LOGVAR(sipmsg) <<this;
		return false;
	}
	assert(0);
	TUWriteHighSideV(sipmsg);
	return true;	// For outbound transactions, TransactionLayer sends all inbound replies to the TU.
}
Example #20
0
void startUnregister(const FullMobileId &msid, L3LogicalChannel *chan)
{
	LOG(DEBUG) <<LOGVAR(msid);
	SipDialog *registrar = getRegistrar();
	SipMessage *request = registrar->makeRegisterMsg(SIPDTUnregister,chan,"",msid,NULL);
	SipRegisterTU *reg = new SipRegisterTU(SipRegisterTU::KindUnRegister,registrar,(TranEntryId)0,request);
	delete request;		// sctInitRegisterTransaction made a copy.  Kind of wasteful.
	reg->sctStart();
}
Example #21
0
// Return TRUE to delete it.
bool SipClientTrLayer::TLPeriodicServiceV()
{
	LOG(DEBUG) << LOGVAR(mTimerDK) <<LOGVAR(mTimerBF) <<LOGVAR(mTimerAE);
	ScopedLock lock(mstLock);
	if (mstState == stInitializing) { return false; }
	if (mstState == stTerminated) { return true; }
	// The timerDK is the time in the Completed state, and used just to suck up additional incoming replies.
	if (mTimerDK.expired()) { stDestroyV(); return true; }	// The transaction completed, a message was sent to layer3, so we just exit.
	if (mTimerBF.expired()) {
		if (mstState == stCallingOrTrying || mstState == stProceeding) {
			stFail(408); // 408 - SIP Timeout.  Must send a fail message to layer3.
		}
		TUTimeoutV();
		stDestroyV();
		return true;
	}
	if (mstState == stCallingOrTrying && mTimerAE.expired()) { stWrite(&mstOutRequest); mTimerAE.setDouble(); }
	return false;
}
Example #22
0
void SACCHLogicalChannel::l2sendf(const L3Frame& frame)
{
	SAPI_t sap = frame.getSAPI();
	devassert(SAPIsSacch(sap));
	if (sap != SAPI3Sacch) { LOG(NOTICE) << "unexpected"<<LOGVAR(sap)<<" in "<<LOGVAR(frame); }
	LOG(INFO) <<channelDescription() <<LOGVAR(sap) <<LOGVAR(chtype()) <<" " <<frame;
	switch (frame.primitive()) {
		case L3_ESTABLISH_REQUEST:
			// Fall through.
		case L3_DATA:
		case L3_UNIT_DATA:
		case L3_RELEASE_REQUEST:
		case L3_HARDRELEASE_REQUEST:
			mL3In.write(new L3Frame(frame));
			return;
		default:
			assert(0);
	}
}
Example #23
0
// Return true if the current CCCH was used.
bool CCCHLogicalChannel::ccchServiceQueue()
{
    // Update the time when the next CCCH frame will be sent.
    // All the l2sendm/l2sendp calls below block using waitToSend()
    // on the mPrevWriteTime set by the getNextWriteTime call.
    mCcchNextWriteTime = getNextWriteTime();
    if (gBTS.btsHold()) {
        return false;
    }

    // Is this CCCH used for pages?  We determine this by looking at the frame number within the 51-multiframe.
    int paging_block_index = mRevPCH[mCcchNextWriteTime.FN() % 51];


    if (paging_block_index >= 0 && processPages()) {
        return true;
    }

    // We did not use this CCCH for a page, so lets look for something else to send.
    if (processRaches()) {
        return true;	// We used this CCCH.
    }

    // GPRS messages may be in DRX mode or not.
    // If they are in DRX mode, move them to a paging queue and set foundSomeNewPages.
    bool foundSomeNewPages = false;

    for (NewPagingEntry *gprsIt = gGprsCcchMessageQ.itBegin(); gprsIt; ) {
        NewPagingEntry *gprsMsg = gprsIt;	// This is redundant; the items are not currently modified by iteration.
        LOG(DEBUG) << "processing"<<LOGVAR(gprsMsg);
        GSM::Time drxBeginTime(gprsMsg->mDrxBegin);
        if (mCcchNextWriteTime >= drxBeginTime) {
            // This MS is now in DRX mode.  Move the message to the paging queue.
            gprsIt = gGprsCcchMessageQ.itRemove(gprsIt);
            gPagingQ.addPage(gprsMsg);
            foundSomeNewPages = true;
            continue;
        }
        // Woo hoo!  Send out the message.
        if (sendGprsCcchMessage(gprsMsg,mCcchNextWriteTime)) {
            gprsIt = gGprsCcchMessageQ.itRemove(gprsIt);
            delete gprsMsg;
            return true;	// We used this CCCH.
        } else {
            // Failed.  That means we were unable to make a reservation for some reason.
            // While unlikely, it is possible that a reservation on one channel failed while reservations on other
            // channels would succeed, so dont block the entire queue due to this one failure, keep going.
            gprsIt = gGprsCcchMessageQ.itSkip(gprsIt);
        }
    }

    if (foundSomeNewPages);	// shut up gcc

    return false;	// We have not used this CCCH.
}
Example #24
0
static int opensock(uint32_t sgsnIp, int sgsnPort /*,int bssgPort*/ )
{
	//int fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
	int sockfd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
	if (sockfd < 0) {
		LOG(ERR) << "Could not create socket for BSSGP";
		return -1;
	}


	/******
	{	// We dont want to bind here.  connect will pick a port for us.
		int32_t bssgIp = INADDR_ANY;
		struct sockaddr_in myAddr;
		memset(&myAddr,0,sizeof(myAddr));	// be safe.
		myAddr.sin_family = AF_INET;
		myAddr.sin_addr.s_addr = htonl(bssgIp);
		myAddr.sin_port = htons(bssgPort);
		if (0 != bind(sockfd,(sockaddr*)&myAddr,sizeof(myAddr))) {
			LOG(ERR) << "Could not bind NS socket to" 
				<< LOGVAR(bssgIp) << LOGVAR(bssgPort) << LOGVAR(errno);
			close(sockfd);
			return -1;
		}
	}
	****/

	struct sockaddr_in sgsnAddr;
	memset(&sgsnAddr,0,sizeof(sgsnAddr));
	sgsnAddr.sin_family = AF_INET;
	sgsnAddr.sin_addr.s_addr = sgsnIp;	// This is already in network order.
	sgsnAddr.sin_port = htons(sgsnPort);
	if (0 != connect(sockfd,(sockaddr*)&sgsnAddr,sizeof(sgsnAddr))) {
		LOG(ERR) << "Could not connect NS socket to"
			<< LOGVAR(sgsnIp) << LOGVAR(sgsnPort) << LOGVAR(errno);
		close(sockfd);
		return -1;
	} else {
		GPRSLOG(1) << "connected to SGSN at "<< inet_ntoa(sgsnAddr.sin_addr) <<" port "<<sgsnPort;
	}
	return sockfd;
}
Example #25
0
static int BSTLVParse(ByteType *data, int &rp,
	IEIType::type expected_ieitype, int expected_length)
{
	int received_ieitype = data[rp++];
	int received_length = data[rp++];
	if (received_ieitype != expected_ieitype || received_length != expected_length) {
		int bstype = data[NSMsg::UnitDataHeaderLen];
		LOG(ERR) << "Error in BSSG msg type="<<bstype
			<<LOGVAR(expected_ieitype) <<LOGVAR(expected_length)
			<<LOGVAR(received_ieitype) <<LOGVAR(received_length);
		return 0;
	}
	int result;
	switch (received_length) {
	case 1: result = data[rp++]; break;
	case 2: result = getntohs(&data[rp]); rp+=2; break;
	case 4: result = getntohl(&data[rp]); rp+=4; break;
	default: assert(0);
	}
	return result;
}
Example #26
0
void L2LogicalChannel::l2sendf(const L3Frame& frame)
{
	SAPI_t sap = frame.getSAPI();
	assert(sap == SAPI0 || sap == SAPI3 || sap == SAPI0Sacch || sap == SAPI3Sacch);
	WATCHINFO("l2sendf "<<channelDescription() <<LOGVAR(sap) <<LOGVAR(chtype()) <<" " <<frame);
	if (SAPIsSacch(sap)) { getSACCH()->l2sendf(frame); return; }
	switch (frame.primitive()) {
		case L3_ESTABLISH_REQUEST:
			if (sap != SAPI3) { LOG(NOTICE) << "unexpected"<<LOGVAR(sap)<<" in "<<LOGVAR(frame); }
			break;
		case L3_DATA:
		case L3_UNIT_DATA:
			break;
		case L3_RELEASE_REQUEST:
			// Normal release initiated by layer3.
			if (sap == SAPI0) { 	// Total deactivation requested.
				startNormalRelease();
				return;
			}
			break;
		case L3_HARDRELEASE_REQUEST:
			// This is a full immediate release.
			if (sap == SAPI0) {
				immediateRelease();
				return;
			}
			LOG(NOTICE) << "unexpected"<<LOGVAR(sap)<<" in "<<LOGVAR(frame);
			break;
		default:
			assert(0);
			return;
	}
	mL3In.write(new L3Frame(frame));
}
Example #27
0
void L2LogicalChannel::writeToL3(L3Frame*frame)
{
	LOG(DEBUG) <<this <<LOGVAR(*frame);
	switch (frame->primitive()) {
		case L3_ESTABLISH_INDICATION:
		case L3_ESTABLISH_CONFIRM:
		case HANDOVER_ACCESS:
		case L3_DATA:
		case L3_UNIT_DATA:
			break;
		case MDL_ERROR_INDICATION:
			// Normal release procedure initiated by handset, or due to error at LAPDm level.
			// An error is handled identically to a normal release, because the handset may still be listening to us
			// even though we lost contact with it, and we want to tell it to release as gracefully as possible
			// even though the channel condition may suck.
			if (frame->getSAPI() == SAPI0) {
				// Release on host chan sap 0 is a total release.  We will start the release now.
				// FIXME: Are we supposed to wait for any pending SMS requests on SACCH to clear first?
				startNormalRelease();
			} else {
				// We dont kill the whole link for SAP3 release.
				// Pass the message on to layer3 to abort whatever transaction is running on SAP3
			}
			break;
		case L3_DATA_CONFIRM:			// Sent from LAPDm when data delivered, but we dont care.
			WATCHINFO(this <<LOGVAR2("sap",frame->getSAPI()) <<LOGVAR(frame));
			delete frame;
			return;
		case L3_RELEASE_INDICATION:
		case L3_RELEASE_CONFIRM:			// Sent from LAPDm when link release is confirmed, but we dont care.
			if (frame->getSAPI() == SAPI0) {
				mT3109.reset();
				mT3111.set();
			}
			break;
		default:
			assert(0);
	}
	mL3Out.write(frame);
}
Example #28
0
// OLD: Send this loop an NS_BLOCK message to kill this thread off;
// and we dont normally use that NS message.
// There is a BSSG-level BVC_BLOCK message that we would use to do a temporary data block.
void *sendServiceLoop(void *arg)
{
	BSSGMain *bssgp = (BSSGMain*)arg;
	NSPDUType::type nstype = NSPDUType::NS_RESET;	// init to anything.
	do {
		NSMsg *ulmsg = bssgp->mbsTxQ.read();
		// It is already wrapped up in an NS protocol.
		int msgsize = ulmsg->size();
		ssize_t result = send(bssgp->mbsSGSockfd,ulmsg->begin(),msgsize,0);
		nstype = ulmsg->getNSPDUType();
		int debug_level = 1; //(nstype == NSPDUType::NS_UNITDATA) ? 1 : 4;
		if (GPRS::GPRSDebug & debug_level) {
			GPRSLOG(debug_level) << "BSSG ===> sendServiceLoop sent "
				<<nstype<<LOGVAR(msgsize)<<ulmsg->str()<<timestr();
		}
		if (result != msgsize) {
			LOG(ERR) << "BSSGP invalid send result" << LOGVAR(result) << LOGVAR(msgsize);
		}
		delete ulmsg;
	} while (bssgp->mbsIsOpen /*&& nstype != NSPDUType::NS_BLOCK*/);
	return NULL;
}
Example #29
0
void SACCHLogicalChannel::sacchInit()
{
	LOG(DEBUG) <<this;
	if (mL1) mL1->l1init();		// (pat) L1FEC::l1init()
	neighborClearMeasurements();
	//mAverageRXLEV_SUB_SERVICING_CELL = 0;
	// Just make sure any stray messages are flushed when we reactivate the channel.
	while (L3Message *straymsg = mTxQueue.readNoBlock()) { delete straymsg; }
	mMeasurementResults = L3MeasurementResults();	// clear it
#if USE_SEMAPHORE
	//cout << descriptiveString() << " POST " <<sem_getvalue(&mOpenSignal,&sval) <<LOGVAR(sval) <<endl;
	int sval, semstat= sem_getvalue(&mOpenSignal,&sval);
	LOG(DEBUG) << descriptiveString() << " SEM_POST " <<LOGVAR(semstat) <<LOGVAR(sval);
	sem_post(&mOpenSignal);	// Note: you must open the L2LogicalChannel before starting the SACCH service loop.
#endif
	if (!mSacchRunning) {
		mSacchRunning=true;
		// This thread pushes data through lapdm and all the way to L1Encoder.
		mSacchServiceThread.start2((void*(*)(void*))SACCHServiceLoop,this,12000*sizeof(void*));
	}
	LOG(DEBUG);
}
Example #30
0
SACCHLogicalChannel::SACCHLogicalChannel(
		unsigned wCN,
		unsigned wTN,
		const MappingPair& wMapping,
		/*const*/ L2LogicalChannel *wHost)
		: mHost(wHost)
{
	mSACCHL1 = new SACCHL1FEC(wCN,wTN,wMapping);
	mL1 = mSACCHL1;
	// SAP0 is RR, SAP3 is SMS
	// SAP1 and SAP2 are not used.
	L2LAPDm *sap0 = new SACCHL2(1,SAPI0);	// derived from L2LAPDm
	L2LAPDm *sap3 = new SACCHL2(1,SAPI3);
	sapInit(sap0,sap3);
	connect(mL1);
	//assert(mSACCH==NULL);
#if USE_SEMAPHORE
	int sval, semstat= sem_getvalue(&mOpenSignal,&sval);
	LOG(DEBUG) << descriptiveString() << " SEM_INIT " <<LOGVAR(semstat) <<LOGVAR(sval);
	sem_init(&mOpenSignal,0,0);
#endif
}