forked from RangeNetworks/openbts
-
Notifications
You must be signed in to change notification settings - Fork 44
/
Copy pathL3StateMachine.h
204 lines (166 loc) · 8.04 KB
/
L3StateMachine.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
/**@file Declarations for Circuit Switched State Machine and related classes. */
/*
* Copyright 2013, 2014 Range Networks, Inc.
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing
* information for this specific distribution.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
// TODO: To avoid bugs where the state machines get stuck,
// send a HARDRELEASE from L3 when mT3109 expires, which is the uplink activity counter in XCCHL1Decoder,
// which is used for TCHFACCHL1Decoder, SDDCHL1Decoder and SACCHL1Decoder.
// Technique is similar to: if (mUpstream!=NULL) mUpstream->writeLowSide(L2Frame(ESTABLISH));
// Currently, the TCH handler in Control dir polls radioFailure() which eventually checks mT3109.
// For SDCCH, the ch just gets reused after mT3109 expiry, and L3 is not notified - we just hope it is no longer in use after 30s.
#ifndef CSL3STATEMACHINE_H
#define CSL3STATEMACHINE_H
#include <map>
#include <Logger.h>
#include <Interthread.h>
#include <Timeval.h>
#include <GSMTransfer.h>
#include "ControlCommon.h"
#include "L3Utils.h"
#include "L3TermCause.h"
//#include <GSML3CommonElements.h>
//#include <GSML3MMElements.h>
//#include <GSML3CCElements.h>
//#include <GSML3Message.h> // Doesnt this poor L3Message get lonely? When apparently there are multiple L3MMMessages and L3CCMessages?
#include <GSML3MMMessages.h>
#include <GSML3CCMessages.h>
#include <GSML3RRMessages.h>
//#include <SIPDialog.h>
namespace SIP { class SipDialog; };
// These are only for use inside state machines:
#define PROCLOG(level) LOG(level)<<machText()
#define PROCLOG2(level,state) LOG(level) <<LOGHEX(state)<<machText()<<" "
namespace Control {
using namespace GSM;
class TranEntry;
class MMContext;
extern void L3DCCHLoop(L3LogicalChannel*dcch, L3Frame *frame);
#if UNUSED_BUT_SAVE_FOR_UMTS
typedef InterthreadQueue<GenericL3Msg> CSL3StateMachineFifo;
#endif
// This is a return state from a state machine.
struct MachineStatus {
// There are only 4 things a state machine procedure can do on return.
// Any error returns have to map to one of these four.
enum MachineStatusCode {
MachineCodeOK, // continue the procedure, meaning return to L3 message handler and wait for the next message.
MachineCodePopMachine, // return to previous procedure on stack
MachineCodeQuitTran, // Pop all machines from stack and remove the transaction. This is the normal exit from a completed procedure.
MachineCodeQuitChannel, // Drop the channel, which kills all transactions on this channel.
MachineCodeUnexpectedState, // Unexpected message or state was not handled by the current state machine.
};
MachineStatusCode msCode;
TermCause msCause; // If it is QuitTran or QuitChannel.
bool operator==(MachineStatus &other) { return msCode == other.msCode; }
bool operator!=(MachineStatus &other) { return msCode != other.msCode; }
MachineStatus(MachineStatusCode code) { msCode = code; }
static MachineStatus QuitTran(TermCause wCause) {
MachineStatus result(MachineCodeQuitTran);
result.msCause = wCause;
return result;
}
static MachineStatus QuitChannel(TermCause wCause) {
MachineStatus result(MachineCodeQuitChannel);
result.msCause = wCause;
return result;
}
};
std::ostream& operator<<(std::ostream& os, MachineStatus::MachineStatusCode state);
// These ones have no arguments so they might as well be constants.
extern MachineStatus MachineStatusOK, MachineStatusPopMachine, MachineStatusAuthorizationFail;
extern MachineStatus MachineStatusAuthorizationFail, MachineStatusUnexpectedState;
//extern MachineStatus MachineStatusQuitChannel;
//extern MachineStatus MachineStatusQuitTran;
struct MachineStatusQuitTran : MachineStatus {
//MachineStatusQuitTran(GSM::CCCause wcause) : MachineStatus(MachineCodeQuitTran) { mCCCause = wCCcause; }
};
// A base class for the individual Procedure state machines.
// Formerly this contained state so had to be unique for each state machine.
DEFINE_MEMORY_LEAK_DETECTOR_CLASS(MachineBase,MemCheckMachineBase)
class MachineBase : public MemCheckMachineBase
{
friend class TranEntry;
friend class ProcCommon;
protected:
int mPopState; // If we push into a procedure, save the return location here.
public:
// Args are the L3Procedure we are calling and the state in the current procedure to which we will return when nextProcedure is popped.
MachineStatus machPush( MachineBase*wCalledProcedure, int wNextState);
// The one and only TranEntry that is running this procedure.
// The CallHold and CallWaiting will have multiple TransactionEntries and multiple procedures.
private: TranEntry *mTran;
// No TranEntry yet? Then no L3Procedure can be started.
protected:
MachineBase(TranEntry *wTran): mTran(wTran) {
mPopState = 0; // unnecessary but neat.
}
void setTran(TranEntry *wTran) { mTran = wTran; }
TranEntry *tran() const { return mTran; }
MMContext *getContext() const;
MachineBase *currentProcedure() { return this; }
MachineStatus callMachStart(MachineBase* wProc, unsigned startState=0);
void timerStart(L3TimerId tid, unsigned val, int nextState); // Executes nextState on expiry.
void timerStop(L3TimerId tid);
void timerStopAll();
bool timerExpired(L3TimerId tid); // Is it expired?
public:
virtual ~MachineBase() {} // Must be virtual to allow derived L3Procedures to delete themselves properly.
void machText(std::ostream&) const;
string machText() const;
// accessors
L3LogicalChannel *channel() const; // may be SDCCH or FACCH.
CallState getGSMState() const;
void setGSMState(CallState);
SIP::SipDialog *getDialog() const;
void setDialog(SIP::SipDialog*dialog);
unsigned getL3TI() const;
bool isL3TIValid() const;
virtual const char *debugName() const = 0;
MachineStatus unexpectedState(int state, const L3Message*l3msg);
MachineStatus closeChannel(RRCause rrcause,Primitive prim,TermCause cause);
void machineErrorMessage(int level, int state, const L3Message *l3msg, const SIP::DialogMessage *sipmsg, const char *format);
virtual void handleTerminationRequest() {} // Procedure can over-ride this to do nicer cleanup.
// Methods for Procedure States.
// The primary entry point for the state machine at the specified state.
// State 0 is always reserved as the initial start state.
// If this invocation is due to a message arrival, it is included as an argument.
// The other possibilities are: timeout, popProcedure, or initial invocation in state 0.
// The state machine must implement one of the following methods, depending on how much control it wants over its input.
virtual MachineStatus machineRunState(int state, const GSM::L3Message *l3msg=NULL, const SIP::DialogMessage *sipmsg=NULL);
virtual MachineStatus machineRunState1(int state, const GSM::L3Frame *frame=NULL, const GSM::L3Message *l3msg=NULL, const SIP::DialogMessage *sipmsg=NULL);
//virtual MachineStatus procRunSipMsg(const SIP::DialogMessage *sipmsg) = 0;
MachineStatus dispatchSipDialogMsg(const SIP::DialogMessage *msg);
MachineStatus dispatchL3Msg(const GSM::L3Message *msg);
MachineStatus dispatchTimeout(L3Timer *timer);
MachineStatus dispatchFrame(const L3Frame *frame, const L3Message *l3msg);
};
#if UNUSED_BUT_SAVE_FOR_UMTS
// TODO: This class could go away. I am keeping it around to see if it is useful for UMTS.
// This is the outer layer state machine to process CS L3 Messages.
// CS [Circuit Switched] L3 messages are specified in 3GPP 4.08, as opposed to PS [Packet Switched] L3 messages handled by the SGSN.
// This is part of the L3 rewrite.
class CSL3StateMachine
{
CSL3StateMachineFifo mCSL3Fifo;
Thread* mCSL3Thread;
public:
CSL3StateMachine();
//void csl3ServiceLoop();
//void csl3Start();
// Put a message on the queue of messages to process.
//bool csl3Write(GenericL3Msg *msg); // return TRUE if the message was handled.
};
extern CSL3StateMachine gCSL3StateMachine;
#endif
}; // namespace Control
#endif