/* $Id$ G N O K I I A Linux/Unix toolset and driver for Nokia mobile phones. Copyright (C) 1999, 2000 Hugh Blemings & Pavel Janík ml. Released under the terms of the GNU GPL, see file COPYING for more details. The development of RLP protocol is sponsored by SuSE CR, s.r.o. (Pavel use the SIM card from SuSE for testing purposes). Actual implementation of RLP protocol. Based on GSM 04.22 version 7.1.0, downloadable from www.etsi.org (if you register with them) $Log$ Revision 1.1.1.1 2001/11/25 21:59:08 short :pserver:cvs@pserver.samba.org:/cvsroot - gnokii - Sun Nov 25 22:56 CET 2001 Revision 1.5 2001/03/26 23:39:36 pkot Minor updates: - Windows INLINE patch (Manfred Jonsson) - patch to configure.in to compile under FreeBSD (Panagiotis Astithas) - other cleanups (me) Revision 1.4 2001/03/13 01:23:18 pkot Windows updates (Manfred Jonsson) Revision 1.3 2001/02/21 19:57:00 chris More fiddling with the directory layout Revision 1.2 2001/02/17 22:40:51 chris ATA support */ #include #include #include #include #include "data/rlp-common.h" #include "data/rlp-crc24.h" #include "gsm-common.h" /* For GSM error and RLP send function. */ #include "misc.h" /* For u8, u32 etc. */ #ifdef WIN32 #define INLINE __inline #else #define INLINE inline #endif /* Our state machine which handles all of nine possible states of RLP machine. */ void MAIN_STATE_MACHINE(RLP_F96Frame *frame, RLP_F96Header *header); /* This is the type we are just handling. */ RLP_FrameTypes CurrentFrameType; /* Current state of RLP state machine. */ RLP_State CurrentState=RLP_S0; /* We start at ADM and Detached */ /* Next state of RLP state machine. */ RLP_State NextState; /* Pointer to Send function that sends frame to phone. */ bool (*RLPSendFunction)(RLP_F96Frame *frame, bool out_dtx); /* Pointer to Passup function which returns data/inds */ int (*RLP_Passup)(RLP_UserInds ind, u8 *buffer, int length); /* State variables - see GSM 04.22, Annex A, section A.1.2 */ RLP_StateVariable UA_State; RLP_StateVariable UI_State; RLP_StateVariable Ackn_State; RLP_StateVariable Poll_State; RLP_StateVariable Poll_xchg; RLP_StateVariable SABM_State; RLP_StateVariable DISC_State; RLP_StateVariable DM_State; /* FIXME - not handled */ RLP_StateVariable XI_R_State; RLP_StateVariable XID_C_State; RLP_StateVariable XID_R_State; RLP_StateVariable TEST_R_State; u8 VR=0; u8 VA=0; u8 VS=0; u8 VD=0; u8 DISC_Count; u8 DTX_VR; RLP_FrameTypes DTX_SF; #define RLP_M 62 RLP_Data R[RLP_M]; RLP_Data S[RLP_M]; RLP_StateVariable SABM_State; int SABM_Count; RLP_UserRequestStore UserRequests; u8 Poll_Count=0; /* For now timing is done based on a frame reception rate of 20ms */ /* Serge has measured it as 18.4ms */ #define RLP_T_Scaling 2 /* Timers - a value of -1 means not set */ /* To set, timer is loaded with RLP_Timeout1_Limit/RLP_T_Scaling. */ /* Each received frame (including NULLS / errors) any >0 timer is decrease */ int T; int T_RCVS[RLP_M]; bool UA_FBit=true; bool Ackn_FBit=false; bool DM_FBit=false; /* FIXME - not handled */ bool RRReady=false; bool LRReady=true; /* FIXME - not handled (as if we couldn't keep up with 9600bps :-) */ bool DISC_PBit=false; u8 LastStatus=0xff; /* Last Status byte */ /* RLP Parameters. FIXME: Reset these - e.g. when entering state 0 */ u8 RLP_SEND_WS = RLP_M-1; u8 RLP_RCV_WS = RLP_M-1; u8 RLP_Timeout1_Limit = 55; u8 RLP_N2 = 15; /* Maximum number of retransmisions. GSM spec says 6 here, but Nokia will XID this. */ u8 RLP_T2=0; u8 RLP_VersionNumber=0; /****** Externally called functions ********/ /*******************************************/ /* Function to initialise RLP code. Main purpose for now is to set the address of the RLP send function in the API code. */ void RLP_Initialise(bool (*rlp_send_function)(RLP_F96Frame *frame, bool out_dtx), int (*rlp_passup)(RLP_UserInds ind, u8 *buffer, int length)) { int i; RLPSendFunction = rlp_send_function; RLP_Passup=rlp_passup; UserRequests.Conn_Req=false; UserRequests.Attach_Req=false; UserRequests.Conn_Req_Neg=false; UserRequests.Reset_Resp=false; UserRequests.Disc_Req=false; CurrentState=RLP_S0; T=-1; for (i=0;i= 0) ? result : result + RLP_M; * } */ /* Check value is within range */ static bool InWindow(u8 val, u8 lower, u8 upper) { /* allow for one level of wrapping round */ if (lower>=RLP_M) lower-=RLP_M; if (upper>=RLP_M) upper-=RLP_M; if (val>=RLP_M) val-=RLP_M; /* .......L*****U....... */ if (lower <= upper) return (val >= lower) && (val <= upper); /* ******U.........L***** */ return (val <= upper) || (val >= lower); } void RLP_Init_link_vars(void) { int i; Ackn_State=_idle; Poll_State=_idle; Poll_Count=0; Poll_xchg=_idle; SABM_State=_idle; DISC_State=_idle; RRReady=true; /* This seems a bit strange but it's what the spec says... */ VA=0; VR=0; VS=0; VD=0; LastStatus=0xff; for(i=0;i23) { S[VD].Data[0]=0x1e; size=24; } else S[VD].Data[0]=size; memcpy(&S[VD].Data[1],buffer,size); if (size!=24) S[VD].Data[size+1]=0x1f; S[VD].State=_send; VD=Incr(VD); } } /* FIXME: Remove this after finishing. */ void X(RLP_F96Frame *frame) { int i; for (i=0; i<30; i++) printf("byte[%2d]: %02x\n", i, *( (u8 *)frame+i)); } void ResetAllT_RCVS(void) { int i; for (i=0;i>5); switch (FrameType) { /* Unnumbered frames. Be careful - some commands are used as commands only, so we have to set C/R bit later. We should not allow user for example to send SABM as response because in the spec is: The SABM encoding is used as command only. */ case RLPFT_U_SABM: frame.Header[0]|=0xf8; /* See page 11 of the GSM 04.22 spec - 0 X X 1 1 1 1 1 */ frame.Header[1]|=0x01; /* 1 P/F M1 M2 M3 M4 M5 X */ SetCRBit; /* The SABM encoding is used as a command only. */ SetPFBit; /* It is always used with the P-bit set to "1". */ PackM(RLPU_SABM); break; case RLPFT_U_UA: frame.Header[0]|=0xf8; frame.Header[1]|=0x01; ClearCRBit; /* The UA encoding is used as a response only. */ PackM(RLPU_UA); break; case RLPFT_U_DISC: frame.Header[0]|=0xf8; frame.Header[1]|=0x01; SetCRBit; /* The DISC encoding is used as a command only. */ PackM(RLPU_DISC); break; case RLPFT_U_DM: frame.Header[0]|=0xf8; frame.Header[1]|=0x01; ClearCRBit; /* The DM encoding is used as a response only. */ PackM(RLPU_DM); break; case RLPFT_U_NULL: frame.Header[0]|=0xf8; frame.Header[1]|=0x01; PackM(RLPU_NULL); break; case RLPFT_U_UI: frame.Header[0]|=0xf8; frame.Header[1]|=0x01; PackM(RLPU_UI); break; case RLPFT_U_XID: frame.Header[0]|=0xf8; frame.Header[1]|=0x01; SetPFBit; /* XID frames are always used with the P/F-bit set to "1". */ PackM(RLPU_XID); break; case RLPFT_U_TEST: frame.Header[0]|=0xf8; frame.Header[1]|=0x01; PackM(RLPU_TEST); break; case RLPFT_U_REMAP: frame.Header[0]|=0xf8; frame.Header[1]|=0x01; ClearPFBit; /* REMAP frames are always used with P/F-bit set to "0". */ PackM(RLPU_REMAP); break; case RLPFT_S_RR: frame.Header[0]|=0xf0; /* See page 11 of the GSM 04.22 spec - 0 X X 1 1 1 1 1 */ frame.Header[1]|=0x01; /* 1 P/F ...N(R)... */ PackNR; PackS(RLPS_RR); break; case RLPFT_S_REJ: frame.Header[0]|=0xf0; frame.Header[1]|=0x01; PackNR; PackS(RLPS_REJ); break; case RLPFT_S_RNR: frame.Header[0]|=0xf0; frame.Header[1]|=0x01; PackNR; PackS(RLPS_RNR); break; case RLPFT_S_SREJ: frame.Header[0]|=0xf0; frame.Header[1]|=0x01; PackNR; PackS(RLPS_SREJ); break; case RLPFT_SI_RR: PackNR; PackNS; PackS(RLPS_RR); break; case RLPFT_SI_REJ: PackNR; PackNS; PackS(RLPS_REJ); break; case RLPFT_SI_RNR: PackNR; PackNS; PackS(RLPS_RNR); break; case RLPFT_SI_SREJ: PackNR; PackNS; PackS(RLPS_SREJ); break; default: break; } /* Store FCS in the frame. */ RLP_CalculateCRC24Checksum((u8 *)&frame, 27, frame.FCS); // X(&frame); if (RLPSendFunction) RLPSendFunction(&frame, OutDTX); } /* Check_input_PDU in Serge's code. */ void RLP_DisplayF96Frame(RLP_F96Frame *frame) { int count; RLP_F96Header header; if (T>=0) T--; for (count=0;count=0) T_RCVS[count]--; CurrentFrameType=RLPFT_BAD; if (!frame) { /* no frame provided, drop through to state machine anyway */ } else if (RLP_CheckCRC24FCS((u8 *)frame, 30) == true) { /* Here we have correct RLP frame so we can parse the field of the header to out structure. */ RLP_DecodeF96Header(frame, &header); switch (header.Type) { case RLPFT_U: /* Unnumbered frames. */ #ifdef RLP_DEBUG fprintf(stdout, "Unnumbered Frame [$%02x%02x] M=%02x ", frame->Header[0], frame->Header[1], header.M); #endif switch (header.M) { case RLPU_SABM : if (header.CR == 0 || header.PF == 0) break; #ifdef RLP_DEBUG fprintf(stdout, "Set Asynchronous Balanced Mode (SABM) "); #endif CurrentFrameType=RLPFT_U_SABM; break; case RLPU_UA: if (header.CR == 1) break; #ifdef RLP_DEBUG fprintf(stdout, "Unnumbered Acknowledge (UA) "); #endif CurrentFrameType=RLPFT_U_UA; break; case RLPU_DISC: if (header.CR == 0) break; #ifdef RLP_DEBUG fprintf(stdout, "Disconnect (DISC) "); #endif CurrentFrameType=RLPFT_U_DISC; break; case RLPU_DM: if (header.CR == 1) break; #ifdef RLP_DEBUG fprintf(stdout, "Disconnected Mode (DM) "); #endif CurrentFrameType=RLPFT_U_DM; break; case RLPU_UI: #ifdef RLP_DEBUG fprintf(stdout, "Unnumbered Information (UI) "); #endif CurrentFrameType=RLPFT_U_UI; break; case RLPU_XID: #ifdef RLP_DEBUG fprintf(stdout, "Exchange Information (XID) \n"); RLP_DisplayXID(frame->Data); #endif CurrentFrameType=RLPFT_U_XID; break; case RLPU_TEST: #ifdef DEBUG fprintf(stdout, "Test (TEST) "); #endif CurrentFrameType=RLPFT_U_TEST; break; case RLPU_NULL: #ifdef DEBUG fprintf(stdout, "Null information (NULL) "); #endif CurrentFrameType=RLPFT_U_NULL; break; case RLPU_REMAP: #ifdef DEBUG fprintf(stdout, "Remap (REMAP) "); #endif CurrentFrameType=RLPFT_U_REMAP; break; default : #ifdef RLP_DEBUG fprintf(stdout, _("Unknown!!! ")); #endif CurrentFrameType=RLPFT_BAD; break; } break; case RLPFT_S: /* Supervisory frames. */ #ifdef RLP_DEBUG fprintf(stdout, "Supervisory Frame [$%02x%02x] S=0x%x N(R)=%d ", frame->Header[0], frame->Header[1], header.S, header.Nr); #endif switch (header.S) { case RLPS_RR: #ifdef RLP_DEBUG fprintf(stdout, "RR"); #endif CurrentFrameType=RLPFT_S_RR; break; case RLPS_REJ: #ifdef RLP_DEBUG fprintf(stdout, "REJ"); #endif CurrentFrameType=RLPFT_S_REJ; break; case RLPS_RNR: #ifdef RLP_DEBUG fprintf(stdout, "RNR"); #endif CurrentFrameType=RLPFT_S_RNR; break; case RLPS_SREJ: #ifdef RLP_DEBUG fprintf(stdout, "SREJ"); #endif CurrentFrameType=RLPFT_S_SREJ; break; default: #ifdef DEBUG fprintf(stdout, _("BAD")); #endif CurrentFrameType=RLPFT_BAD; break; } break; default: #ifdef RLP_DEBUG fprintf(stdout, "Info+Supervisory Frame [$%02x%02x] S=0x%x N(S)=%d N(R)=%d ", frame->Header[0], frame->Header[1], header.S, header.Ns, header.Nr); #endif switch (header.S) { case RLPS_RR: #ifdef RLP_DEBUG fprintf(stdout, "RR"); #endif CurrentFrameType=RLPFT_SI_RR; break; case RLPS_REJ: #ifdef RLP_DEBUG fprintf(stdout, "REJ"); #endif CurrentFrameType=RLPFT_SI_REJ; break; case RLPS_RNR: #ifdef RLP_DEBUG fprintf(stdout, "RNR"); #endif CurrentFrameType=RLPFT_SI_RNR; break; case RLPS_SREJ: #ifdef RLP_DEBUG fprintf(stdout, "SREJ"); #endif CurrentFrameType=RLPFT_SI_SREJ; break; default: #ifdef DEBUG fprintf(stdout, "BAD"); #endif CurrentFrameType=RLPFT_BAD; break; } break; } #ifdef RLP_DEBUG /* Command/Response and Poll/Final bits. */ fprintf(stdout, " C/R=%d P/F=%d", header.CR, header.PF); #endif #ifdef DEBUG /* Information. */ if (CurrentFrameType!=RLPFT_U_NULL) { fprintf(stdout, "\n"); for (count = 0; count < 25; count ++) { if (isprint(frame->Data[count])) fprintf(stdout, "[%02x%c]", frame->Data[count], frame->Data[count]); else fprintf(stdout, "[%02x ]", frame->Data[count]); if (count == 15) fprintf(stdout, "\n"); } } #endif #ifdef RLP_DEBUG /* FCS. */ fprintf (stdout, " FCS: %02x %02x %02x\n\n", frame->FCS[0], frame->FCS[1], frame->FCS[2]); fflush(stdout); #endif } else { /* RLP Checksum failed - don't we need some statistics about these failures? Nothing is printed, because in the first stage of connection there are too many bad RLP frames... */ #ifdef DEBUG fprintf(stdout, _("Frame FCS is bad. Ignoring...\n")); #endif } MAIN_STATE_MACHINE(frame, &header); /* Y:= outblock(); */ return; } /* FIXME: real TEST_Handling - we do not handle TEST yet. */ void TEST_Handling() { } /* FIXME: better XID_handling - but this will answer a XID command. */ bool XID_Handling (RLP_F96Frame *frame, RLP_F96Header *header) { u8 count; u8 type; u8 length; if (CurrentFrameType == RLPFT_U_XID) { count=0; while (frame->Data[count] !=0) { type=frame->Data[count] >> 4; length=frame->Data[count] & 0x0f; count++; switch (type) { case 0x01: /* RLP Version Number */ RLP_VersionNumber=frame->Data[count]; count+=length; break; case 0x02: /* Interworking Function (IWF) to Mobile Station (MS) window size */ if (frame->Data[count]>=1 && frame->Data[count]Data[count]; count+=length; break; case 0x03: /* MS to IWF window size */ if (frame->Data[count]>=1 && frame->Data[count]Data[count]; count+=length; break; case 0x04: /* Acknowledgement Timer (T1). */ RLP_Timeout1_Limit=frame->Data[count]; count+=length; break; case 0x05: /* Retransmission attempts (N2). */ RLP_N2=frame->Data[count]; count+=length; break; case 0x06: /* Reply delay (T2). */ RLP_T2=frame->Data[count]; count+=length; break; case 0x07: /* Compression - not yet! */ break; default: count+=length; break; } } /* Now reassemble a reply */ count=0; memset(frame->Data,0x00,25); /* Makes debugging easier */ /* Version Number - force to 0 for now */ RLP_VersionNumber=0; frame->Data[count++]=0x11; frame->Data[count++]=RLP_VersionNumber; /* Window sizes */ frame->Data[count++]=0x21; frame->Data[count++]=RLP_RCV_WS; frame->Data[count++]=0x31; frame->Data[count++]=RLP_SEND_WS; /* Acknowledgement Timer (T1). */ frame->Data[count++]=0x41; frame->Data[count++]=RLP_Timeout1_Limit; /* Retransmission attempts (N2). */ frame->Data[count++]=0x51; frame->Data[count++]=RLP_N2; /* Reply delay (T2). */ frame->Data[count++]=0x61; frame->Data[count++]=RLP_T2; XID_R_State = _send; return true; } return false; } bool Send_TXU(RLP_F96Frame *frame, RLP_F96Header *header) { #ifdef DEBUG // fprintf(stdout, _("Send_TXU()\n")); // fprintf(stdout, _("XID_R_State=%d\n"), XID_R_State); #endif /* if (RLP_UserEvent(TEST_R_State)) { RLP_SendF96Frame(RLPFT_U_TEST, false, TEST_R_FBit, 0, 0, TEST_R_Data, false); return true; } else */ if (XID_R_State == _send && frame) { RLP_SendF96Frame(RLPFT_U_XID, false, true, 0, 0, frame->Data, false); XID_R_State = _idle; return true; } /* else if ((XID_C_State == _send ) && (Poll_xchg == _idle)) { RLP_SendF96Frame(RLPFT_U_XID, true, true, 0, 0, XID_C_Data, false); XID_C_State = _wait; T_XID = 1; Poll_xchg = _wait; return true; } else if (RLP_UserEvent(UI_State)) { RLP_SendF96Frame(RLPFT_U_UI, true, false, 0, 0, NULL, false); return true; } */ return false; } /* Deliver data */ void RLP_DeliverAllInSeqIF() { int i,j; do { if ((R[VR].Data[0] & 0xE0)!=LastStatus) { LastStatus=(R[VR].Data[0] & 0xE0); RLP_Passup(StatusChange,&LastStatus,0); } j=0; i=R[VR].Data[0] & 0x1f; if (i==0x1e) j=24; if (i<0x18) j=i; /* FIXME - should check for more data in the frame */ RLP_Passup(Data,R[VR].Data+1,j); R[VR].State=_idle; VR=Incr(VR); } while (R[VR].State==_rcvd); } /* Mark any missing information frames between VR and Ns*/ void RLP_MarkMissingIF(u8 Ns) { u8 i; for (i=VR; i!=Ns; i=Incr(i)) { if (R[i].State==_idle) R[i].State=_srej; /* bug in spec, fig A.23 */ } } /* Information frame handler */ bool RLP_I_Handler(RLP_F96Frame *frame, RLP_F96Header *header) { if ((header->CR) && (header->PF)) return true; /* If the window size is 61, a received frame must have a sequence number between VR and VR+60 */ if (!InWindow(header->Ns,VR,VR+RLP_RCV_WS-1)) return true; if (header->Ns==VR) { /* This is not in the spec but I think it is necessary */ if (R[header->Ns].State==_wait) T_RCVS[header->Ns]=-1; R[VR].State=_rcvd; memcpy(R[VR].Data,frame->Data,25); RLP_DeliverAllInSeqIF(); Ackn_State=_send; } else { /* Out of sequence, cause a SREJ */ if (R[header->Ns].State==_wait) T_RCVS[header->Ns]=-1; R[header->Ns].State=_rcvd; memcpy(R[header->Ns].Data,frame->Data,25); RLP_MarkMissingIF(header->Ns); } return false; } /* Mark acknowledged send frames */ void RLP_AdvanceVA(u8 Nr) { while (VA!=Nr) { S[VA].State=_idle; VA=Incr(VA); } } /* Decrease VS back down to Nr since these have not been acknowledged */ void RLP_DecreaseVS(u8 Nr) { while (VS!=Nr) { VS=Decr(VS); S[VS].State=_send; } } /* Supervisory frame handling */ void RLP_S_Handler(RLP_F96Frame *frame, RLP_F96Header *header) { u8 i; if ((header->CR) && (header->PF)) { /* Special exchange (ie. error) - counter? */ #ifdef RLP_DEBUG fprintf(stdout, "Got Poll command\n"); #endif Ackn_State=_send; Ackn_FBit=true; for (i=0; iPF==0) return; if ((CurrentFrameType==RLPFT_S_SREJ) || (CurrentFrameType==RLPFT_S_REJ) || (CurrentFrameType==RLPFT_SI_SREJ) || (CurrentFrameType==RLPFT_SI_REJ)) return; RLP_DecreaseVS(header->Nr); Poll_State=_idle; Poll_xchg=_idle; } switch (CurrentFrameType){ case RLPFT_S_RR: case RLPFT_SI_RR: RLP_AdvanceVA(header->Nr); RRReady=true; break; case RLPFT_S_RNR: case RLPFT_SI_RNR: RLP_AdvanceVA(header->Nr); RRReady=false; break; case RLPFT_S_REJ: case RLPFT_SI_REJ: RLP_AdvanceVA(header->Nr); RRReady=true; RLP_DecreaseVS(header->Nr); break; case RLPFT_S_SREJ: case RLPFT_SI_SREJ: S[header->Nr].State=_send; T=-1; return; default: break; } if (VA==VS) T=-1; } /* Find the first SREJ frame */ bool RLP_SREJSlot(u8 *x) { u8 i; for (i=Incr(VR); i!=VR; i=Incr(i)) if (R[i].State==_srej) { *x=i; return true; } return false; } /* Check if any SREJ frames need sending, if not send the next in line */ bool RLP_PrepareDataToTransmit(u8 *p) { u8 i; for (i=VA; i!=VS; i=Incr(i)) if (S[i].State==_send) { *p=i; S[i].State=_wait; return true; } if (S[VS].State!=_send) return false; if (!InWindow(VS,VA,VA+RLP_SEND_WS-1)) return false; *p=VS; S[VS].State=_wait; VS=Incr(VS); return true; } /* Send a SREJ command */ void RLP_SendSREJ(u8 x) { u8 k; if ((Poll_xchg==_idle) && (Poll_State==_send)) { #ifdef RLP_DEBUG fprintf(stdout, "Sending SREJ with poll\n"); #endif RLP_SendF96Frame(RLPFT_S_SREJ, true, true, x , 0 , NULL, false); R[x].State=_wait; RLP_SetTimer(&T_RCVS[x]); Poll_Count++; Poll_State=_wait; Poll_xchg=_wait; RLP_SetTimer(&T); } else if (RRReady && RLP_PrepareDataToTransmit(&k)) { #ifdef RLP_DEBUG fprintf(stdout, "Sending SREJ for %d along with frame %d\n",x,k); #endif RLP_SendF96Frame(RLPFT_SI_SREJ, true, false, x , k , S[k].Data, false); R[x].State=_wait; RLP_SetTimer(&T_RCVS[x]); RLP_SetTimer(&T); } else { #ifdef RLP_DEBUG fprintf(stdout, "Sending SREJ for %d\n",x); #endif RLP_SendF96Frame(RLPFT_S_SREJ, true, false, x , 0 , NULL, false); R[x].State=_wait; RLP_SetTimer(&T_RCVS[x]); } } /* Send a command */ void RLP_Send_XX_Cmd(RLP_FrameTypes type) { u8 k; if ((Poll_xchg!=_wait) && (Poll_State==_send)) { RLP_SendF96Frame(type, true, true, VR , 0 , NULL, false); #ifdef RLP_DEBUG fprintf(stdout, "Sending Comd %x with Poll\n",type); #endif Ackn_State=_idle; Poll_Count++; Poll_State=_wait; Poll_xchg=_wait; RLP_SetTimer(&T); } else if (RRReady && RLP_PrepareDataToTransmit(&k)) { #ifdef RLP_DEBUG fprintf(stdout, "Sending Comd %x with frame %d\n",type,k); #endif RLP_SendF96Frame(type+4, true, false, VR , k , S[k].Data, false); Ackn_State=_idle; RLP_SetTimer(&T); } else { #ifdef RLP_DEBUG if (type!=9) fprintf(stdout, "Sending Comd %x\n",type); #endif RLP_SendF96Frame(type, true, false, VR , 0 , NULL, false); Ackn_State=_idle; DTX_SF=type; DTX_VR=VR; /* As v7.1.0 spec */ } } /* Send a Response */ void RLP_Send_XX_Resp(RLP_FrameTypes type) { u8 k; if (RRReady && RLP_PrepareDataToTransmit(&k)) { #ifdef RLP_DEBUG fprintf(stdout, "Sending Resp %x with frame %d\n",type+4,k); #endif RLP_SendF96Frame(type+4, false, true, VR , k , S[k].Data, false); Ackn_State=_idle; Ackn_FBit=false; RLP_SetTimer(&T); } else { #ifdef RLP_DEBUG fprintf(stdout, "Sending Resp %x\n",type); #endif RLP_SendF96Frame(type, false, true, VR , 0 , NULL, false); Ackn_State=_idle; Ackn_FBit=false; } } /* Decide which frame to use and send it - currently only used in state 4 */ void RLP_SendData() { u8 x; if (UA_State==_send) { RLP_SendF96Frame(RLPFT_U_UA, false, UA_FBit, 0 , 0 , NULL, false); UA_State=_idle; } else if (Ackn_FBit==true) { #ifdef RLP_DEBUG printf("About to send Poll resp\n"); #endif if (LRReady) RLP_Send_XX_Resp(RLPFT_S_RR); else RLP_Send_XX_Resp(RLPFT_S_RNR); } else if (RLP_SREJSlot(&x)) RLP_SendSREJ(x); else if (LRReady) RLP_Send_XX_Cmd(RLPFT_S_RR); else RLP_Send_XX_Cmd(RLPFT_S_RNR); } void MAIN_STATE_MACHINE(RLP_F96Frame *frame, RLP_F96Header *header) { int i; switch (CurrentState) { /***** RLP State 0. *****/ /* ADM and Detached. This is the initial state after power on. As long as the RLP entity is "Detached", DISC(P) and/or SABM at the lower interface is acted upon by sending DM(P) or DM(1). Any other stimulus at the lower interface is ignored. This state can be exited only with Attach_Req. */ case RLP_S0: #ifdef DEBUG fprintf(stdout, _("RLP state 0.\n")); #endif switch (CurrentFrameType) { case RLPFT_U_DISC: RLP_SendF96Frame(RLPFT_U_DM, false, header->PF, 0, 0, NULL, false); break; case RLPFT_U_SABM: RLP_SendF96Frame(RLPFT_U_DM, false, true, 0, 0, NULL, false); break; default: RLP_SendF96Frame(RLPFT_U_NULL, false, false, 0, 0, NULL, false); if (RLP_GetUserRequest(Attach_Req)) { NextState=RLP_S1; UA_State=_idle; } break; } break; /***** RLP State 1. *****/ /* ADM and Attached. The RLP entity is ready to established a connection, either by initiating the connection itself (Conn_Req) or by responding to an incoming connection request (SABM). Upon receiving a DISC PDU, the handling of the UA response is initiated. */ case RLP_S1: #ifdef DEBUG fprintf(stdout, _("RLP state 1.\n")); #endif if (!XID_Handling(frame, header)) { switch(CurrentFrameType) { case RLPFT_U_TEST: TEST_Handling(); break; case RLPFT_U_SABM: RLP_Passup(Conn_Ind,NULL,0); NextState=RLP_S3; break; case RLPFT_U_DISC: UA_State=_send; UA_FBit=header->PF; break; case RLPFT_BAD: /* If we get a bad frame we can still respond with SABM */ default: if (RLP_GetUserRequest(Conn_Req)) { SABM_State=_send; SABM_Count=0; NextState=RLP_S2; } break; } } if (!Send_TXU(frame, header)) { if (UA_State == _send) { RLP_SendF96Frame(RLPFT_U_UA, false, UA_FBit, 0, 0, NULL, false); UA_State=_idle; } else RLP_SendF96Frame(RLPFT_U_NULL, false, false, 0, 0, NULL, false); } break; /***** RLP State 2. *****/ case RLP_S2: #ifdef DEBUG fprintf(stdout, _("RLP state 2.\n")); #endif if (!XID_Handling(frame, header)) { switch(CurrentFrameType) { case RLPFT_U_TEST: TEST_Handling(); break; case RLPFT_U_SABM: /* T=0; Conn_Conf=true; UA_State=_send; UA_FBit=true; Init_Link_Vars; NextState=4; */ break; case RLPFT_U_DISC: /* T=0; DISC_Ind; UA_State=_send; UA_FBit=header->PF; NextState=RLP_S1; */ break; case RLPFT_U_UA: #ifdef DEBUG fprintf(stdout, _("UA received in RLP state 2.\n")); #endif if (SABM_State == _wait && header->PF) { T=-1; // Conn_Conf=true; // Init_Link_Vars; NextState=RLP_S4; } break; case RLPFT_U_DM: if (SABM_State == _wait && header->PF) { Poll_xchg=_idle; // Conn_Conf_Neg=true; NextState=RLP_S1; } break; default: if (T == RLP_Timeout1_Limit) { Poll_xchg=_idle; if (SABM_Count>RLP_N2) NextState=RLP_S8; SABM_State=_send; } break; } } if (!Send_TXU(frame, header)) { if (SABM_State == _send && Poll_xchg == _idle) { RLP_SendF96Frame(RLPFT_U_SABM, true, true, 0, 0, NULL, false); SABM_State=_wait; SABM_Count++; Poll_xchg=_wait; T=1; } else RLP_SendF96Frame(RLPFT_U_NULL, false, false, 0, 0, NULL, false); } if (RLP_GetUserRequest(Disc_Req)) { T=-1; DISC_State=_send; DISC_Count=0; DISC_PBit=(Poll_xchg==_idle); NextState=5; } break; /***** RLP State 3. *****/ case RLP_S3: #ifdef DEBUG fprintf(stdout, _("RLP state 3.\n")); #endif if (!XID_Handling(frame, header)) { switch(CurrentFrameType) { case RLPFT_U_TEST: TEST_Handling(); break; case RLPFT_U_DISC: RLP_Passup(Disc_Ind,NULL,0); UA_State=_send; UA_FBit=header->PF; NextState=RLP_S1; break; default: if (RLP_GetUserRequest(Conn_Req)) { UA_State=_send; UA_FBit=true; NextState=RLP_S4; RLP_Init_link_vars(); } else if (RLP_GetUserRequest(Conn_Req_Neg)) { DM_State=_send; /* FIXME - code to handle DM_State - missing from spec? */ DM_FBit=true; NextState=RLP_S1; } break; } } if (!Send_TXU(frame, header)) { if (UA_State == _send) { RLP_SendF96Frame(RLPFT_U_UA, false, UA_FBit, 0, 0, NULL, false); UA_State=_idle; } else RLP_SendF96Frame(RLPFT_U_NULL, false, false, 0, 0, NULL, false); } if (RLP_GetUserRequest(Disc_Req)) { T=-1; DISC_State=_send; DISC_Count=0; DISC_PBit=(Poll_xchg==_idle); NextState=5; } break; /***** RLP State 4. *****/ case RLP_S4: #ifdef DEBUG fprintf(stdout, _("RLP state 4.\n")); #endif if (!XID_Handling(frame, header)) { switch (CurrentFrameType) { case RLPFT_U_TEST: TEST_Handling(); break; case RLPFT_U_DISC: T=-1; ResetAllT_RCVS(); RLP_Passup(Disc_Ind,NULL,0); UA_State=_send; UA_FBit=header->PF; NextState=RLP_S1; break; case RLPFT_U_SABM: T=-1; ResetAllT_RCVS(); RLP_Passup(Reset_Ind,NULL,0); NextState=RLP_S7; break; case RLPFT_S_RR: case RLPFT_S_RNR: case RLPFT_S_REJ: case RLPFT_S_SREJ: /* Should check here for unsolicited Fbit */ /* Spec says: "Nr must be within the set of not yet acknowledged I-frames or it must be the next possible frame number." That's VA..VS-1 or VS, i.e. VA..VS */ if (!InWindow(header->Nr,VA,VS)) break; RLP_S_Handler(frame,header); break; case RLPFT_SI_RR: case RLPFT_SI_RNR: case RLPFT_SI_REJ: case RLPFT_SI_SREJ: /* Should check here for unsolicited Fbit */ if (!InWindow(header->Nr,VA,VS)) break; if (!RLP_I_Handler(frame,header)) RLP_S_Handler(frame,header); break; default: break; } } for (i=0;iRLP_N2) { #ifdef RLP_DEBUG fprintf(stdout, "N2 Errors in State 4\n"); #endif } Poll_State=_send; Poll_Count++; } } if (!Send_TXU(frame,header)) { if (UA_State == _send) { RLP_SendF96Frame(RLPFT_U_UA, false, UA_FBit, 0, 0, NULL, false); UA_State=_idle; } else RLP_SendData(); } /* Load any data from the Send ringbuffer into the send slots */ RLP_AddRingBufferDataToSlots(); #ifdef RLP_DEBUG // if (CurrentFrameType!=RLPFT_BAD) fprintf(stdout, "VD=%d, VA=%d, VS=%d, VR=%d\n",VD,VA,VS,VR); #ifdef RLP_DEBUG_STATE { int zzz; if(UA_State!=_idle) printf("[UA_State %d]",UA_State); if(UI_State!=_idle) printf("[UI_State %d]",UI_State); if(Ackn_State!=_idle) printf("[Ackn_State %d]",Ackn_State); if(Poll_State!=_idle) printf("[Poll_State %d]",Poll_State); if(Poll_xchg!=_idle) printf("[Poll_xchg %d]",Poll_xchg); if(SABM_State!=_idle) printf("[SABM_State %d]",SABM_State); if(DISC_State!=_idle) printf("[DISC_State %d]",DISC_State); if(DM_State!=_idle) printf("[DM_State %d]",DM_State); if(XI_R_State!=_idle) printf("[XI_R_State %d]",XI_R_State); if(XID_C_State!=_idle) printf("[XID_C_State %d]",XID_C_State); if(XID_R_State!=_idle) printf("[XID_R_State %d]",XID_R_State); if(TEST_R_State!=_idle) printf("[TEST_R_State %d]",TEST_R_State); printf("S: "); for (zzz=0; zzzPF)) { if (DISC_PBit==true) Poll_xchg=_idle; T=-1; NextState=1; } break; case RLPFT_U_DISC: T=-1; UA_State=_send; UA_FBit=header->PF; NextState=1; break; default: break; } } if (!Send_TXU(frame,header)) { if ((DISC_State!=_wait) && !((DISC_PBit==true) && (Poll_xchg==_wait))) { RLP_SendF96Frame(RLPFT_U_DISC, true, DISC_PBit, 0, 0, NULL, false); if (DISC_PBit==true) Poll_xchg=_wait; DISC_State=_wait; DISC_Count++; RLP_SetTimer(&T); } else RLP_SendF96Frame(RLPFT_U_NULL, false, false, 0, 0, NULL, false); } if (T==0) { if (DISC_PBit==1) Poll_xchg=_idle; DISC_Count++; if (DISC_Count>RLP_N2) { #ifdef RLP_DEBUG fprintf(stdout, "N2 error in State 5!\n"); #endif } DISC_State=_send; } break; /***** RLP State 6. *****/ /* We should only get here after a Reset_Req which is not yet supported */ case RLP_S6: #ifdef DEBUG fprintf(stdout, _("RLP state 6 - not yet implemented!\n")); #endif if (!XID_Handling(frame, header)) { switch (CurrentFrameType) { default: break; } } if (!Send_TXU(frame,header)) { } if (RLP_GetUserRequest(Disc_Req)) { T=-1; DISC_State=_send; DISC_Count=0; DISC_PBit=(Poll_xchg==_idle); NextState=5; } break; /***** RLP State 7. *****/ case RLP_S7: #ifdef DEBUG fprintf(stdout, _("RLP state 7.\n")); #endif if (!XID_Handling(frame, header)) { switch (CurrentFrameType) { case RLPFT_U_DISC: RLP_Passup(Disc_Ind,NULL,0); UA_State=_send; UA_FBit=header->PF; NextState=RLP_S1; break; default: break; } } if (RLP_GetUserRequest(Reset_Resp)){ UA_State=_send; UA_FBit=1; RLP_Init_link_vars(); NextState=RLP_S4; } if (!Send_TXU(frame,header)) { RLP_SendF96Frame(RLPFT_U_NULL, false, false, 0, 0, NULL, false); } if (RLP_GetUserRequest(Disc_Req)) { T=-1; DISC_State=_send; DISC_Count=0; DISC_PBit=(Poll_xchg==_idle); NextState=5; } break; default: #ifdef DEBUG fprintf(stdout, _("DEBUG: Unknown RLP state!\n")); #endif break; } CurrentState=NextState; } /* Given a pointer to an RLP XID frame, display contents in human readable form. Note for now only Version 0 and 1 are supported. Fields can appear in any order and are delimited by a zero type field. This function is the exact implementation of section 5.2.2.6, Exchange Identification, XID of the GSM specification 04.22. */ void RLP_DisplayXID(u8 *frame) { int count = 25; /* Sanity check */ u8 type, length; fprintf(stdout, "XID: "); while ((*frame !=0) && (count >= 0)) { type = *frame >> 4; length = *frame & 0x0f; switch (type) { case 0x01: /* RLP Version Number, probably 1 for Nokia. */ frame += length; fprintf(stdout, "Ver %d ", *frame); break; case 0x02: /* IWF to MS window size */ frame += length; fprintf(stdout, "IWF-MS %d ", *frame); break; case 0x03: /* MS to IWF window size. */ frame += length; fprintf(stdout, "MS-IWF %d ", *frame); break; case 0x04: /* Acknowledgement Timer (T1). */ frame += length; fprintf(stdout, "T1 %dms ", *frame * 10); break; case 0x05: /* Retransmission attempts (N2). */ frame += length; fprintf(stdout, "N2 %d ", *frame); break; case 0x06: /* Reply delay (T2). */ frame += length; fprintf(stdout, "T2 %dms ", *frame * 10); break; case 0x07: /* Compression. */ frame ++; fprintf(stdout, "Comp [Pt=%d ", (*frame >> 4) ); fprintf(stdout, "P0=%d ", (*frame & 0x03) ); frame ++; fprintf(stdout, "P1l=%d ", *frame); frame ++; fprintf(stdout, "P1h=%d ", *frame); frame ++; fprintf(stdout, "P2=%d] ", *frame); break; default: frame += length; fprintf(stdout, "Unknown! type=%02x, length=%02x", type, length); break; } count --; frame ++; } return; } /* Given a pointer to an F9.6 Frame, split data out into component parts of header and determine frame type. */ void RLP_DecodeF96Header(RLP_F96Frame *frame, RLP_F96Header *header) { /* Poll/Final bit. */ if ((frame->Header[1] & 0x02)) header->PF = true; else header->PF = false; /* Command/Response bit. */ if ((frame->Header[0] & 0x01)) header->CR = true; else header->CR = false; /* Send Sequence Number. */ header->Ns = frame->Header[0] >> 3; if ((frame->Header[1] & 0x01)) header->Ns |= 0x20; /* Most significant bit. */ /* Determine frame type. See the section 5.2.1 in the GSM 04.22 specification. */ switch (header->Ns) { case 0x3f: /* Frames of type U, unnumbered frames. */ /* U frames have M1, ..., M5 stored in the place of N(R). */ header->Type = RLPFT_U; header->M = (frame->Header[1] >> 2) & 0x1f; return; /* For U frames, we do not need N(R) and bits S1 and S2. */ case 0x3e: /* Frames of type S, supervisory frames. */ header->Type = RLPFT_S; break; default: /* Frames of type I+S, numbered information transfer ans supervisory frames combined. */ header->Type = RLPFT_IS; break; } /* Receive Sequence Number N(R). */ header->Nr = frame->Header[1] >> 2; /* Status bits (S1 and S2). */ header->S = (frame->Header[0] >> 1) & 0x03; return; }