Ejemplo n.º 1
0
void L2LAPDm::receiveSFrameRR(const L2Frame& frame)
{
	// Caller should hold mLock.
	OBJLOG(INFO) << "state=" << mState << " " << frame;
	// GSM 04.06 3.8.5.
	// Q.921 3.6.6.
	// vISDN datalink.c:lapd_handle_sframe_rr
	// Again, since LAPDm allows only one outstanding frame
	// (k=1), this is a lot simpler than in LAPD.
	switch (mState) {
		case ContentionResolution:
			mState = LinkEstablished;
			// continue to next case...
		case LinkEstablished:
			// "inquiry response procedure"
			// Never actually seen that happen in GSM...
			if ((frame.CR()!=mC) && (frame.PF())) {
				sendSFrameRR(true);
			}
			processAck(frame.NR());
			break;
		default:
			// ignore
			return;
	}
}
Ejemplo n.º 2
0
void L2LAPDm::receiveUFrameDISC(const L2Frame& frame)
{
	// Caller should hold mLock.
	OBJLOG(INFO) << "state=" << mState << " " << frame;
	mEstablishmentInProgress = false;
	switch (mState) {
		case AwaitingEstablish:
			clearState();
			break;
		case LinkReleased:
			// GSM 04.06 5.4.5
			sendUFrameDM(frame.PF());
			clearState();
			break;
		case ContentionResolution:
		case LinkEstablished:
			// Shut down the link and ack with UA.
			// GSM 04.06 5.4.4.2.
			sendUFrameUA(frame.PF());
			clearState();
			break;
		case AwaitingRelease:
			// We can arrive here if both ends sent DISC at the same time.
			// GSM 04.06 5.4.6.1.
			sendUFrameUA(frame.PF());
			break;
		default:
			unexpectedMessage();
			return;
	}
}
Ejemplo n.º 3
0
void L2LAPDm::writeL1Ack(const L2Frame& frame)
{
	// Caller should hold mLock.
	// GSM 04.06 5.4.4.2
	OBJLOG(DEEPDEBUG) <<"L2LAPDm::writeL1Ack " << frame;
	frame.copyTo(mSentFrame);
	mSentFrame.primitive(frame.primitive());
	writeL1(frame);
	mT200.set();
}
Ejemplo n.º 4
0
void SACCHLogicalChannel::writeToL1(const L2Frame& frame)
{
	// The SAP may or may not be present, depending on the channel type.
	OBJLOG(DEBUG) << frame;
	switch (frame.primitive()) {
		case L2_DATA:
			mL1->writeHighSide(frame);
			break;
		default:
			OBJLOG(ERR) << "unhandled primitive " << frame.primitive() << " in L2->L1";
			devassert(0);
	}
}
Ejemplo n.º 5
0
void L2LAPDm::sendUFrameUA(const L2Frame& frame)
{
	// Send UA frame with a echoed payload.
	// This is used in the contention resolution procedure.
	// GSM 04.06 5.4.1.4.
	// The caller need not hold mLock.
	OBJLOG(INFO) << "state=" << mState << " " << frame;
	L2Address address(mR,mSAPI);
	L2Control control(L2Control::UFormat,frame.PF(),0x0C);
	L2Length length(frame.L());
	L2Header header(address,control,length);
	writeL1NoAck(L2Frame(header,frame.L3Part()));
}
Ejemplo n.º 6
0
void L2LAPDm::receiveUFrameUI(const L2Frame& frame)
{
	// The zero-length frame is the idle frame.
	if (frame.L()==0) return;
	OBJLOG(INFO) << "state=" << mState << " " << frame;
	mL3Out.write(new L3Frame(frame,UNIT_DATA));
}
Ejemplo n.º 7
0
void XCCHL1Encoder::sendFrame(const L2Frame& frame)
{
	OBJLOG(DEBUG) << "XCCHL1Encoder " << frame;
	// Make sure there's something down there to take the busts.
	if (mDownstream==NULL) {
		LOG(WARNING) << "XCCHL1Encoder with no downstream";
		return;
	}

	// This comes from GSM 05.03 4.1

	// Copy the L2 frame into u[] for processing.
	// GSM 05.03 4.1.1.
	//assert(mD.size()==headerOffset()+frame.size());
	frame.copyToSegment(mU,headerOffset());

	// Send to GSMTAP (must send mU = real bits !)
	gWriteGSMTAP(ARFCN(),TN(),mNextWriteTime.FN(),
	             typeAndOffset(),mMapping.repeatLength()>51,false,mU);

	// Encode data into bursts
	OBJLOG(DEBUG) << "XCCHL1Encoder d[]=" << mD;
	mD.LSB8MSB();
	OBJLOG(DEBUG) << "XCCHL1Encoder d[]=" << mD;
	encode();			// Encode u[] to c[], GSM 05.03 4.1.2 and 4.1.3.
	interleave();		// Interleave c[] to i[][], GSM 05.03 4.1.4.
	transmit();			// Send the bursts to the radio, GSM 05.03 4.1.5.
}
Ejemplo n.º 8
0
void L2LAPDm::receiveUFrameUA(const L2Frame& frame)
{
	// Caller should hold mLock.
	// GSM 04.06 3.8.8
	// vISDN datalink.c:lapd_socket_handle_uframe_ua

	OBJLOG(INFO) << "state=" << mState << " " << frame;
	if (!frame.PF()) {
		unexpectedMessage();
		return;
	}

	switch (mState) {
		case AwaitingEstablish:
			// We sent SABM and the peer responded.
			clearCounters();
			mState = LinkEstablished;
			mAckSignal.signal();
			mL3Out.write(new L3Frame(ESTABLISH));
			break;
		case AwaitingRelease:
			// We sent DISC and the peer responded.
			clearState();
			break;
		default:
			unexpectedMessage();
			return;
	}
}
Ejemplo n.º 9
0
bool L2LAPDm::stuckChannel(const L2Frame& frame)
{
	// Check for excessive idling.
	if (frame.DCCHIdle()) mIdleCount++;
	else mIdleCount=0;
	return mIdleCount > maxIdle();
}
Ejemplo n.º 10
0
void SDCCHL1Encoder::sendFrame(const L2Frame& frame)
{
	OBJLOG(DEEPDEBUG) << "SDCCHL1Encoder " << frame;
	// Make sure there's something down there to take the busts.
	LOG(INFO) <<"SDCCHL1Encoder  SENDFRAME";
	if (mDownstream==NULL) {
		LOG(WARN) << "XCCHL1Encoder with no downstream";
		return;
	}

	// This comes from GSM 05.03 4.1

	// Copy the L2 frame into u[] for processing.
	// GSM 05.03 4.1.1.
	//assert(mD.size()==headerOffset()+frame.size());
	frame.copyToSegment(mU,headerOffset());
	OBJLOG(DEEPDEBUG) << "XCCHL1Encoder d[]=" << mD;
	mD.LSB8MSB();
	OBJLOG(DEEPDEBUG) << "XCCHL1Encoder d[]=" << mD;
		encode();			// Encode u[] to c[], GSM 05.03 4.1.2 and 4.1.3.
	LOG(INFO) << "SDCCHL1ENCODER ENCODED";
	interleave();		// Interleave c[] to i[][], GSM 05.03 4.1.4.
	LOG(INFO) << "SDCCHL1ENCODER INTERLEAVED";
	encrypt();			// Encrypt i[][] to e[].
	LOG(INFO) << "SDCCHL1ENCODER ENCRYPTED";
	transmit();			// Send the bursts to the radio, GSM 05.03 4.1.5.
	LOG(INFO) << "SDCCHL1ENCODER TRANSMITTED";
	// FIXME: is this FN OK, or do we need to back it up by 4?
	gWriteGSMTAP(ARFCN(),mTN,mPrevWriteTime.FN(),frame);
}
Ejemplo n.º 11
0
void LoopbackSAPMux::writeHighSide(const L2Frame& frame)
{
	OBJLOG(DEBUG) << "Loopback " << frame;
	// Substitute primitive
	L2Frame newFrame(frame);
	unsigned SAPI = frame.SAPI();	
	switch (frame.primitive()) {
		case ERROR: SAPI=0; break;
		case RELEASE: return;
		default: break;
	}
	// Because this is a test fixture, as assert here.
	// If this were not a text fixture, we would print a warning
	// and ignore the frame.
	assert(mUpstream[SAPI]);
	ScopedLock lock(mLock);
	mUpstream[SAPI]->writeLowSide(newFrame);
}
Ejemplo n.º 12
0
void SAPMux::writeLowSide(const L2Frame& frame)
{
	OBJLOG(DEBUG) << frame.SAPI() << " " << frame;
	unsigned SAPI = frame.SAPI();	
	bool data = frame.primitive()==DATA;
	if (data && (!mUpstream[SAPI])) {
		LOG(WARNING) << "received DATA for unsupported SAP " << SAPI;
		return;
	}
	if (data) {
		mUpstream[SAPI]->writeLowSide(frame);
	} else {
		// If this is a non-data primitive, copy it out to every SAP.
		for (int i=0; i<4; i++) {
			if (mUpstream[i]) mUpstream[i]->writeLowSide(frame);
		}
	}
}
Ejemplo n.º 13
0
void L2LAPDm::receiveSFrame(const L2Frame& frame)
{
	// Caller should hold mLock.
	// See GSM 04.06 5.4.1.4.
	mEstablishmentInProgress = false;
	switch (frame.SFrameType()) {
		case L2Control::RRFrame: receiveSFrameRR(frame); break;
		case L2Control::REJFrame: receiveSFrameREJ(frame); break;
		default: unexpectedMessage(); return;
	}
}
Ejemplo n.º 14
0
void L2LAPDm::receiveIFrame(const L2Frame& frame)
{
	// Caller should hold mLock.
	// See GSM 04.06 5.4.1.4.
	mEstablishmentInProgress = false;
	OBJLOG(INFO) << "state=" << mState << " NS=" << frame.NS() << " NR=" << frame.NR() << " " << frame;
	// vISDN datalink.c:lapd_handle_iframe
	// GSM 04.06 5.5.2, 5.7.1
	// Q.921 5.6.2, 5.8.1
	switch (mState) {
		case ContentionResolution:
			mState=LinkEstablished;
			// continue to next case...
		case LinkEstablished:
			processAck(frame.NR());
			if (frame.NS()==mVR) {
				mVR = (mVR+1)%8;
				bufferIFrameData(frame);
				sendSFrameRR(frame.PF());
			} else {
				// GSM 04.06 5.7.1.
				// Q.921 5.8.1.
				sendSFrameREJ(frame.PF());
			}
		case LinkReleased:
			// GSM 04.06 5.4.5
			break;
		default:
			// ignore
			break;
	}
}
Ejemplo n.º 15
0
void L2LAPDm::bufferIFrameData(const L2Frame& frame)
{
	// Concatenate I-frames to form the L3 frame.
	/*
		GSM 04.06 5.5.2 states:
		When a data link layer entity is not in an own receiver busy condition
		and receives a valid I frame whose send sequence number is equal to the
		current receive state variable V(R), the data link layer entity shall: 
			- if the M bit is set to "0", concatenate it with previously
			received frames with the M bit set to "1", if any, and pass the complete
			layer 3 message unit to the layer 3 entity using the primitive
			DL-DATA-INDICATION; 
			- if the M bit is set to "1", store the information field of the frame and
			concatenate it with previously received frames with the M bit set to "1",
			if any (Note: no information is passed to the layer 3 entity); 
	*/

	OBJLOG(DEBUG) << frame;
	if (!frame.M()) {
		// The last or only frame.
		if (mRecvBuffer.size()==0) {
			// The only frame -- just send it up.
			OBJLOG(DEBUG) << "single frame message";
			mL3Out.write(new L3Frame(frame));
			return;
		}
		// The last of several -- concat and send it up.
		OBJLOG(DEBUG) << "last frame of message";
		mL3Out.write(new L3Frame(mRecvBuffer,frame.L3Part()));
		mRecvBuffer.clear();
		return;
	}

	// One segment of many -- concat.
	// This is inefficient but simple.
	mRecvBuffer = L3Frame(mRecvBuffer,frame.L3Part());
	OBJLOG(DEBUG) <<"buffering recvBuffer=" << mRecvBuffer;
}
Ejemplo n.º 16
0
void XCCHL1Encoder::writeHighSide(const L2Frame& frame)
{
	switch (frame.primitive()) {
		case DATA:
			// Encode and send data.
			if (!active()) { LOG(INFO) << "XCCHL1Encoder::writeHighSide sending on non-active channel"; }
			resync();
			sendFrame(frame);
			break;
		case ESTABLISH:
			// Open both sides of the link.
			// The phone is waiting to see the idle pattern.
			open();
			if (sibling()) sibling()->open();
			return;
		case RELEASE:
			// Normally, we get here after a DISC-DM handshake in L2.
			// Close both sides of the link, knowing that the phone will do the same.
			close();
			if (sibling()) sibling()->close();
			break;
		case HARDRELEASE:
			// This means that a higher layer released the link,
			// with certainty that is has been cleared of activity.
			close();
			if (sibling()) sibling()->close(true);
			break;
		case ERROR:
			// If we got here, it means the link failed in L2 after several ack timeouts.
			// Close the tx side and just let the receiver L1 time out on its own.
			// Otherwise, we risk recycling the channel while the phone's still active.
			close();
			break;
		default:
			LOG(ERR) << "unhandled primitive " << frame.primitive() << " in L2->L1";
			assert(0);
	}
}
Ejemplo n.º 17
0
void L2LAPDm::receiveUFrame(const L2Frame& frame)
{
	// Also see vISDN datalink.c:lapd_socket_handle_uframe
	OBJLOG(DEBUG) << frame;
	switch (frame.UFrameType()) {
		case L2Control::SABMFrame: receiveUFrameSABM(frame); break;
		case L2Control::DMFrame: receiveUFrameDM(frame); break;
		case L2Control::UIFrame: receiveUFrameUI(frame); break;
		case L2Control::DISCFrame: receiveUFrameDISC(frame); break;
		case L2Control::UAFrame: receiveUFrameUA(frame); break;
		default:
			OBJLOG(NOTICE) << " could not parse U-Bits " << frame;
			unexpectedMessage();
			return;
	}
}
Ejemplo n.º 18
0
void L2LAPDm::receiveUFrameDM(const L2Frame& frame)
{
	// Caller should hold mLock.
	OBJLOG(INFO) << "state=" << mState << " " << frame;
	// GSM 04.06 5.4.5
	if (mState==LinkReleased) return;
	// GSM 04.06 5.4.6.3
	if (!frame.PF()) return;

	// Because we do not support multiple TEIs in LAPDm,
	// and because we should never get DM in response to SABM,
	// this procedure is much simpler that in vISDN LAPD.
	// Unlike LAPD, there's also no reason for LAPDm to not be
	// able to establish ABM, so if we get this message
	// we know the channel is screwed up.

	clearState();
}
Ejemplo n.º 19
0
void L2LogicalChannel::writeLowSide(const L2Frame& frame)
{
	// If this is the first good frame of a new transaction,
	// stop T3101 and tell L2 we're alive down here.
	if (mT3101.active()) {
		mT3101.reset();
		// Inform L3 that we are alive down here.
		// This does not block; goes to a InterthreadQueue L2LAPdm::mL1In
		sapWriteFromL1(L2Frame(PH_CONNECT));
	}
	switch (frame.primitive()) {
		case HANDOVER_ACCESS:	// Only send this on SAPI 0.
			writeToL3(new L3Frame(SAPI0,HANDOVER_ACCESS));
			break;
		default:
			sapWriteFromL1(frame);
			break;
	}
}
Ejemplo n.º 20
0
void L2LAPDm::receiveUFrameSABM(const L2Frame& frame)
{
	// Caller should hold mLock.
	// Process the incoming SABM command.
	// GSM 04.06 3.8.2, 5.4.1
	// Q.921 5.5.1.2.
	// Also borrows from vISDN datalink.c:lapd_socket_handle_uframe_sabm.
	OBJLOG(INFO) << "state=" << mState << " " << frame;
	// Ignore frame if P!=1.
	// See GSM 04.06 5.4.1.2.
	if (!frame.PF()) return;
	// Dispatch according to current state.
	// BTW, LAPDm can always enter multiframe mode when requested,
	// so that's another big simplification over ISDN/LAPD.
	switch (mState) {
		case LinkReleased:
			// GSM 04.06 5.4.5, 5.4.1.2, 5.4.1.4
			clearCounters();
			mEstablishmentInProgress = true;
			// Tell L3 what happened.
			mL3Out.write(new L3Frame(ESTABLISH));
			if (frame.L()) {
				// Presence of an L3 payload indicates contention resolution.
				// GSM 04.06 5.4.1.4.
				mState=ContentionResolution;
				mContentionCheck = frame.sum();
				mL3Out.write(new L3Frame(frame.L3Part(),DATA));
				// Echo back payload.
				sendUFrameUA(frame);
			} else {
				mState=LinkEstablished;
				sendUFrameUA(frame.PF());
			}
			break;
		case ContentionResolution:
			// GSM 04.06 5.4.1.4
			// This guards against the remote possibility that two handsets
			// are sending on the same channel at the same time.
			// vISDN's LAPD doesn't need/do this since peers are hard-wired
			if (frame.sum()!=mContentionCheck) break;
			mState=LinkEstablished;
			sendUFrameUA(frame);
			break;
		case AwaitingEstablish:
			// Huh?  This would mean both sides sent SABM at the same time/
			// That should not happen in GSM.
			sendUFrameUA(frame.PF());
			OBJLOG(WARN) << "simulatenous SABM attempts";
			break;
		case AwaitingRelease:
			// If we are awaiting release, we will not enter ABM.
			// So we send DM to indicate that.
			sendUFrameDM(frame.PF());
			break;
		case LinkEstablished:
			// Latency in contention resolution, GSM 04.06 5.4.2.1.
			if (mEstablishmentInProgress) {
				if (frame.L()) sendUFrameUA(frame);
				else sendUFrameUA(frame.PF());
				break;
			}
			if (frame.L())  {
				abnormalRelease();
				break;
			}
			// Re-establishment procedure, GSM 04.06 5.6.3.
			// This basically resets the ack engine.
			// We should not actually see this, as of rev 2.4.
			OBJLOG(WARN) << "reestablishment not really supported";
			sendUFrameUA(frame.PF());
			clearCounters();
			break;
		default:
			unexpectedMessage();
			return;
	}
}