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::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; }
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; } }