--- /dev/null
+/*
+
+ $Id$
+
+ G N O K I I
+
+ A Linux/Unix toolset and driver for Nokia mobile phones.
+
+ 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)
+
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+#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<RLP_M;i++) T_RCVS[i]=-1;
+
+ UA_FBit=true;
+ Ackn_FBit=false;
+ DISC_PBit=false;
+ LastStatus=0xff;
+ Poll_Count=0;
+ VR=0;
+ VA=0;
+ VS=0;
+ VD=0;
+
+ RLP_SEND_WS = RLP_M-1;
+ RLP_RCV_WS = RLP_M-1;
+ RLP_Timeout1_Limit = 55;
+ RLP_N2 = 15;
+ RLP_T2=0;
+ RLP_VersionNumber=0;
+
+}
+
+/* Set a user event */
+/* Called by user program for now */
+
+void RLP_SetUserRequest(RLP_UserRequests type, bool value) {
+
+ switch (type) {
+ case Conn_Req:
+ UserRequests.Conn_Req=value;
+ break;
+ case Attach_Req:
+ UserRequests.Attach_Req=value;
+ break;
+ case Conn_Req_Neg:
+ UserRequests.Conn_Req_Neg=value;
+ break;
+ case Reset_Resp:
+ UserRequests.Reset_Resp=value;
+ break;
+ case Disc_Req:
+ UserRequests.Disc_Req=value;
+ break;
+ default:
+ break;
+ }
+}
+
+
+
+
+/***** Internal functions **********/
+/***********************************/
+
+
+/* Check whether a user event is set */
+
+bool RLP_GetUserRequest(RLP_UserRequests type) {
+
+ bool result=false, *x;
+
+ switch (type) {
+ case Conn_Req:
+ x=&UserRequests.Conn_Req;
+ break;
+ case Attach_Req:
+ x=&UserRequests.Attach_Req;
+ break;
+ case Conn_Req_Neg:
+ x=&UserRequests.Conn_Req_Neg;
+ break;
+ case Reset_Resp:
+ x=&UserRequests.Reset_Resp;
+ break;
+ case Disc_Req:
+ x=&UserRequests.Disc_Req;
+ break;
+ default:
+ x=&result;
+ break;
+ }
+
+ result=*x;
+
+ if ( *x == true )
+ *x=false;
+
+ return result;
+}
+
+void RLP_SetTimer(int *timer)
+{
+ *timer=(int)(RLP_Timeout1_Limit/RLP_T_Scaling);
+}
+
+
+/* Previous sequence number. */
+static INLINE u8 Decr(u8 x)
+{
+ if (x==0)
+ return (RLP_M-1);
+ else
+ return (x-1);
+}
+
+/* Next sequence number. */
+static INLINE u8 Incr(u8 x)
+{
+ if (x==RLP_M-1)
+ return 0;
+ else
+ return (x+1);
+}
+
+/* Difference between sequence numbers. */
+
+/* FIXME: Not used now, so I have commented it out. PJ
+ * static INLINE u8 Diff(u8 x, u8 y)
+ * {
+ * int result = x-y;
+ * return (result >= 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;i<RLP_M;i++) {
+ R[i].State=_idle;
+ S[i].State=_idle;
+ }
+
+}
+
+
+void RLP_AddRingBufferDataToSlots(void)
+{
+ u8 buffer[24];
+ int size;
+
+ while ((S[VD].State==_idle)
+ && ((size=RLP_Passup(GetData,buffer,24))!=0)) {
+ memset(S[VD].Data,0xff,25); /* FIXME - this isn't necessary - but makes debugging easier! */
+ if (size>23) {
+ 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<RLP_M;i++) T_RCVS[i]=-1;
+}
+
+
+
+/* This function is used for sending RLP frames to the phone. */
+
+void RLP_SendF96Frame(RLP_FrameTypes FrameType,
+ bool OutCR, bool OutPF,
+ u8 OutNR, u8 OutNS,
+ u8 *OutData, u8 OutDTX)
+{
+
+ RLP_F96Frame frame;
+ int i;
+
+ frame.Header[0]=0;
+ frame.Header[1]=0;
+
+#define SetCRBit frame.Header[0]|=0x01;
+#define SetPFBit frame.Header[1]|=0x02;
+
+#define ClearCRBit frame.Header[0]&=(~0x01);
+#define ClearPFBit frame.Header[1]&=(~0x02);
+
+ /* If Command/Response bit is set, set it in the header. */
+ if (OutCR)
+ SetCRBit;
+
+
+ /* If Poll/Final bit is set, set it in the header. */
+ if (OutPF)
+ SetPFBit;
+
+
+ /* If OutData is not specified (ie. is NULL) we want to clear frame.Data
+ array for the user. */
+ if (!OutData) {
+
+ frame.Data[0]=0x00; // 0x1f
+
+ for (i=1; i<25; i++)
+ frame.Data[i]=0;
+ }
+ else {
+ for (i=0; i<25; i++)
+ frame.Data[i]=OutData[i];
+ }
+
+#define PackM(x) frame.Header[1]|=((x)<<2);
+#define PackS(x) frame.Header[0]|=((x)<<1);
+#define PackNR frame.Header[1]|=(OutNR<<2);
+#define PackNS frame.Header[0]|=(OutNS<<3);frame.Header[1]|=(OutNS>>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<RLP_M;count++) if (T_RCVS[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]<RLP_M)
+ RLP_RCV_WS=frame->Data[count];
+ count+=length;
+ break;
+ case 0x03: /* MS to IWF window size */
+ if (frame->Data[count]>=1 && frame->Data[count]<RLP_M)
+ RLP_SEND_WS=frame->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; i<RLP_M; i++) R[i].State=_idle;
+ ResetAllT_RCVS();
+ }
+ if (Poll_State!=_idle) {
+ if (header->PF==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;i<RLP_M;i++) if (T_RCVS[i]==0) {
+#ifdef RLP_DEBUG
+ fprintf(stdout, "T_RCVS[%d] Timeout in State 4\n",i);
+#endif
+ R[i].State=_srej;
+ }
+ if (T==0) {
+ T=-1;
+#ifdef RLP_DEBUG
+ fprintf(stdout, "T Timeout in State 4\n");
+#endif
+
+ Poll_xchg=_idle;
+ if (Poll_State==_idle) {
+ Poll_State=_send;
+ Poll_Count=0;
+ }
+ else {
+ if (Poll_Count>RLP_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; zzz<RLP_M; zzz++) printf("%d ",S[zzz].State);
+ printf("\nR: ");
+ for (zzz=0; zzz<RLP_M; zzz++) printf("%d ",R[zzz].State);
+ printf("\nT: %d, T_RCVS: ",T);
+ for (zzz=0; zzz<RLP_M; zzz++) printf("%d ",T_RCVS[zzz]);
+ printf("\n");
+ }
+#endif
+#endif
+
+
+ if (RLP_GetUserRequest(Disc_Req)) {
+ T=-1;
+ ResetAllT_RCVS();
+ DISC_State=_send;
+ DISC_Count=0;
+ DISC_PBit=(Poll_xchg==_idle);
+ NextState=5;
+ }
+
+ break;
+
+
+ /***** RLP State 5. *****/
+
+ case RLP_S5:
+
+#ifdef DEBUG
+ fprintf(stdout, _("RLP state 5.\n"));
+#endif
+
+ if (!XID_Handling(frame, header)) {
+
+ switch (CurrentFrameType) {
+
+ case RLPFT_U_UA:
+ case RLPFT_U_DM:
+ if ((DISC_State==_wait) && (DISC_PBit==header->PF)) {
+ 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;
+}
+
+