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; } }
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; } }
void L2LAPDm::receiveSFrameREJ(const L2Frame& frame) { // Caller should hold mLock. OBJLOG(INFO) << "state=" << mState << " " << frame; // GSM 04.06 3.8.6, 5.5.4 // Q.921 3.7.6, 5.6.4. // vISDN datalink.c:lapd_handle_s_frame_rej. switch (mState) { case ContentionResolution: mState = LinkEstablished; // continue to next case... case LinkEstablished: // FIXME -- The spec says to do this but it breaks multiframe transmission. //mVS = mVA = frame.NR(); processAck(frame.NR()); if (frame.PF()) { if (frame.CR()!=mC) sendSFrameRR(true); else { unexpectedMessage(); return; } } // Since k=1, there's really nothing to retransmit, // other than what was just rejected, so kust stop sending it. sendIdle(); break; default: // ignore break; } // Send an idle frame to clear any repeating junk on the channel. sendIdle(); }
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; } }
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; } }
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())); }
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(); }
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; } }