-
Notifications
You must be signed in to change notification settings - Fork 15
/
Copy pathybts.cpp
11157 lines (10668 loc) · 312 KB
/
ybts.cpp
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
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/**
* ybts.cpp
* This file is part of the Yate-BTS Project http://www.yatebts.com
*
* Yet Another BTS Channel
*
* Yet Another Telephony Engine - Base Transceiver Station
* Copyright (C) 2013-2023 Null Team Impex SRL
*
* 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.
*/
#include <yatephone.h>
#include <yateradio.h>
#ifdef _WINDOWS
#error This module is not for Windows
#endif
#include <sys/stat.h>
#include <sys/wait.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <stdio.h>
#include <syslog.h>
using namespace TelEngine;
namespace { // anonymous
#include "ybts.h"
//#define YBTS_DEBUG_SMS
#ifndef YBTS_DEBUG_SMS
#ifdef DEBUG
#define YBTS_DEBUG_SMS
#endif
#endif
#define BTS_DIR "server/bts"
#define BTS_CMD "mbts"
// Handshake interval (timeout)
#define YBTS_HK_INTERVAL_DEF 60000
#define YBTS_HK_INTERVAL_MIN 20000
#define YBTS_HK_INTERVAL_MAX 300000
// Heartbeat interval
#define YBTS_HB_INTERVAL_DEF 30000
#define YBTS_HB_INTERVAL_MIN 1000
#define YBTS_HB_INTERVAL_MAX 120000
// Heartbeat timeout
#define YBTS_HB_TIMEOUT_DEF 60000
#define YBTS_HB_TIMEOUT_MIN 10000
#define YBTS_HB_TIMEOUT_MAX 180000
// Restart
#define YBTS_RESTART_DEF 120000
#define YBTS_RESTART_MIN 30000
#define YBTS_RESTART_MAX 600000
#define YBTS_RESTART_COUNT_DEF 10
#define YBTS_RESTART_COUNT_MIN 3
// Peer check
#define YBTS_PEERCHECK_DEF 3000
// SMS
#define YBTS_MT_SMS_TIMEOUT_DEF 30000
#define YBTS_MT_SMS_TIMEOUT_MIN 5000
#define YBTS_MT_SMS_TIMEOUT_MAX 60000
// USSD
#define YBTS_USSD_TIMEOUT_DEF 600000
#define YBTS_USSD_TIMEOUT_MIN 30000
// Paging
#define YBTS_PAGING_TIMEOUT_DEF 10000
#define YBTS_PAGING_TIMEOUT_MIN 5000
#define YBTS_PAGING_TIMEOUT_MAX 150000
// GPRS
#define YBTS_GPRS_TIMEOUT_DEF 20000
#define YBTS_GPRS_TIMEOUT_MIN 5000
#define YBTS_GPRS_TIMEOUT_MAX 120000
// Maximum GPRS authentication attempts
#define YBTS_GPRS_MAX_AUTHS 2
#define YBTS_SET_REASON_BREAK(s) { reason = s; break; }
#define NO_CONN_ID 0xffff
// Constant strings
static const String s_message = "Message";
static const String s_type = "type";
static const String s_locAreaIdent = "LAI";
static const String s_PLMNidentity = "PLMNidentity";
static const String s_LAC = "LAC";
static const String s_mobileIdent = "MobileIdentity";
static const String s_imsi = "IMSI";
static const String s_imei = "IMEI";
static const String s_tmsi = "TMSI";
static const String s_cause = "Cause";
static const String s_causeLocation = "location";
static const String s_causeCoding = "coding";
static const String s_cmServType = "CMServiceType";
static const String s_cmMOCall = "MO-call-establishment-or-PM-connection-establishment";
static const String s_cmEmgCall = "emergency-call-establishment";
static const String s_cmSMS = "SMS";
static const String s_cmSS = "SS-activation";
static const String s_facility = "Facility";
static const String s_rlc = "ReleaseComplete";
static const String s_ccSetup = "Setup";
static const String s_ccEmergency = "EmergencySetup";
static const String s_ccProceeding = "CallProceeding";
static const String s_ccProgress = "Progress";
static const String s_ccAlerting = "Alerting";
static const String s_ccConnect = "Connect";
static const String s_ccConnectAck = "ConnectAcknowledge";
static const String s_ccDisc = "Disconnect";
static const String s_ccRel = "Release";
static const String s_ccStatusEnq = "StatusEnquiry";
static const String s_ccStatus = "Status";
static const String s_ccStartDTMF = "StartDTMF";
static const String s_ccStopDTMF = "StopDTMF";
static const String s_ccKeypadFacility = "KeypadFacility";
static const String s_ccHold = "Hold";
static const String s_ccRetrieve = "Retrieve";
static const String s_ccConfirmed = "CallConfirmed";
static const String s_ccCallRef = "TID";
static const String s_ccTIFlag = "TIFlag";
static const String s_ccCalled = "CalledPartyBCDNumber";
static const String s_ccCallState = "CallState";
static const String s_ccProgressInd = "ProgressIndicator";
//static const String s_ccUserUser = "UserUser";
static const String s_ccSsCLIR = "CLIRInvocation";
static const String s_ccSsCLIP = "CLIRSuppresion";
// MAP related
static const String s_mapComp = "component";
static const String s_mapLocalCID = "localCID";
static const String s_mapRemoteCID = "remoteCID";
static const String s_mapCompType = "type";
static const String s_mapOperCode = "operationCode";
static const String s_mapUssdText = "ussd-Text";
// Global
static const String s_peerid = "peerid";
static const String s_targetid = "targetid";
static const String s_handlers = "handlers";
static const String s_error = "error";
static const String s_reason = "reason";
static const String s_noAuth = "noauth";
static const String s_noRoute = "noroute";
static const String s_incomplete = "incomplete";
class YBTSConnIdHolder; // A connection id holder
class YBTSConnAuth; // Interface for connection authenticator
class YBTSConnAuthMt; // MT authenticator
class YBTSConnChan; // Channel associated with a connection
class YBTSThread;
class YBTSThreadOwner;
class YBTSMessage; // YBTS <-> BTS PDU
class YBTSTransport;
class YBTSGlobalThread; // GenObject and Thread descendent
class YBTSConnAuthThread; // Authenticator for MT services
class YBTSLAI; // Holds local area id
class YBTSTid; // Transaction identifier holder
class YBTSConn; // A logical connection
class YBTSLog; // Log interface
class YBTSCommand; // Command interface
class YBTSSignalling; // Signalling interface
class YBTSMedia; // Media interface
class YBTSUE; // A registered equipment
class YBTSLocationUpd; // Running location update from UE
class YBTSSubmit; // MO SMS/SS submit thread
class YBTSSmsInfo; // Holds data describing a pending SMS
class YBTSMtSms; // Holds data describing a pending MT SMS
class YBTSMtSmsList; // A list of MT SMS for the same UE target
class YBTSMM; // Mobility management entity
class YBTSDataSource;
class YBTSDataConsumer;
class YBTSCallDesc;
class YBTSChan;
class YBTSChanThread; // Channel utility thread (authentication)
class YBTSDriver;
class YBTSMsgHandler;
class YBTSGprsAttach;
// ETSI TS 100 940
// Section 8.5 / Section 10.5.3.6 / Annex G
enum RejectCause {
CauseServNotSupp = 32, // Service option not implemented
CauseMMTemporaryFailure = 34, // MM Service temporary out of order
CauseInvalidIE = 96, // Invalid mandatory IE
CauseUnknownMsg = 97, // Unknown or not implemented message
CauseUnexpectedMsg = 98, // Message not compatible with protocol state
CauseProtoError = 111, // Protocol error, unspecified
};
static inline int str2index(const String& name, const String* array)
{
if (!array)
return -1;
for (int i = 0; *array; i++, array++)
if (*array == name)
return i;
return -1;
}
static inline const String& index2str(int index, const String* array)
{
if (!array || index < 0)
return String::empty();
for (int i = 0; *array; i++, array++)
if (i == index)
return *array;
return String::empty();
}
class YBTSConnIdHolder
{
public:
inline YBTSConnIdHolder(uint16_t connId = NO_CONN_ID)
: m_connId(connId)
{}
inline uint16_t connId() const
{ return m_connId; }
inline void setConnId(uint16_t cid)
{ m_connId = cid; }
protected:
uint16_t m_connId;
};
class YBTSDebug
{
public:
inline YBTSDebug(DebugEnabler* enabler = 0, void* ptr = 0)
{ setDebugPtr(enabler,ptr); }
inline void setDebugPtr(DebugEnabler* enabler, void* ptr) {
m_enabler = enabler;
m_ptr = ptr;
}
protected:
DebugEnabler* m_enabler;
void* m_ptr;
};
class YBTSConnAuth
{
friend class YBTSSignalling;
public:
inline YBTSConnAuth(uint16_t connid, int origin)
: m_authSent(false), m_authOk(false), m_authNeedResync(false),
m_origin(origin), m_originUsed(false)
{ authSetConn(connid); }
~YBTSConnAuth();
// Set connection
bool authSetConn(uint16_t connid);
// Send auth request. Wait for completion.
// Return true if sent (a response was receveid of request was dropped)
bool authSend(NamedList& params, String& reason, unsigned int* intervals = 0);
// End authentication
virtual void authEnd(bool ok, const char* error = 0, const String* rsp = 0,
const String* rspExt = 0);
void authHandleRsp(bool ok, const XmlElement& xml);
// Send auth reject
void authReject();
// Set auth params in list
void authSetParams(NamedList& list);
// Clear auth params in list
static void authClearParams(NamedList& list);
protected:
RefPointer<YBTSConn> m_conn; // The connection
bool m_authSent; // Auth sent, waiting for response
bool m_authOk; // Auth response/failure received
bool m_authNeedResync; // Received auth failure with error indicating re-sync
String m_authRsp; // Received auth response
String m_authError; // Received error
int m_origin; // Auth origin
bool m_originUsed; // Origin used, auth sent at least once
private:
YBTSConnAuth() {}
};
class YBTSConnAuthMt : public YBTSConnAuth
{
public:
YBTSConnAuthMt(uint16_t connid, YBTSUE* ue, int origin);
const char* authMt(unsigned int* intervals = 0);
protected:
Message m_msg;
RefPointer<YBTSUE> m_ue;
};
class YBTSThread : public Thread
{
public:
YBTSThread(YBTSThreadOwner* owner, const char* name, Thread::Priority prio = Thread::Normal);
virtual void cleanup();
protected:
virtual void run();
void notifyTerminate();
YBTSThreadOwner* m_owner;
};
class YBTSThreadOwner : public YBTSDebug
{
public:
inline YBTSThreadOwner()
: m_thread(0), m_mutex(0)
{}
void threadTerminated(YBTSThread* th);
virtual void processLoop() = 0;
protected:
bool startThread(const char* name, Thread::Priority prio = Thread::Normal);
void stopThread();
inline void initThreadOwner(Mutex* mutex)
{ m_mutex = mutex; }
YBTSThread* m_thread;
String m_name;
Mutex* m_mutex;
};
class YBTSMessage : public GenObject, public YBTSConnIdHolder
{
public:
inline YBTSMessage(uint8_t pri = 0, uint8_t info = 0, uint16_t cid = NO_CONN_ID,
XmlElement* xml = 0)
: YBTSConnIdHolder(cid),
m_primitive(pri), m_info(info), m_xml(xml), m_error(false)
{}
~YBTSMessage()
{ TelEngine::destruct(m_xml); }
inline const char* name() const
{ return lookup(m_primitive,s_priName); }
inline uint16_t primitive() const
{ return m_primitive; }
inline uint8_t info() const
{ return m_info; }
inline bool hasConnId() const
{ return 0 == (m_primitive & 0x80); }
inline const XmlElement* xml() const
{ return m_xml; }
inline XmlElement* takeXml()
{ XmlElement* x = m_xml; m_xml = 0; return x; }
inline bool error() const
{ return m_error; }
// Parse message. Return 0 on failure
static YBTSMessage* parse(YBTSSignalling* receiver, uint8_t* data, unsigned int len);
// Build a message
static bool build(YBTSSignalling* sender, DataBlock& buf, const YBTSMessage& msg);
static const TokenDict s_priName[];
DataBlock m_data;
protected:
uint8_t m_primitive;
uint8_t m_info;
XmlElement* m_xml;
bool m_error; // Encode/decode error flag
};
class YBTSDataSource : public DataSource, public YBTSConnIdHolder
{
public:
inline YBTSDataSource(const char* format, unsigned int connId, YBTSMedia* media)
: DataSource(format), YBTSConnIdHolder(connId), m_media(media)
{}
protected:
virtual void destroyed();
YBTSMedia* m_media;
};
class YBTSDataConsumer : public DataConsumer, public YBTSConnIdHolder
{
public:
inline YBTSDataConsumer(const char* format, unsigned int connId, YBTSMedia* media)
: DataConsumer(format), YBTSConnIdHolder(connId), m_media(media)
{}
virtual unsigned long Consume(const DataBlock& data, unsigned long tStamp,
unsigned long flags);
protected:
YBTSMedia* m_media;
};
class YBTSTransport : public GenObject, public YBTSDebug
{
friend class YBTSLog;
friend class YBTSCommand;
friend class YBTSSignalling;
friend class YBTSMedia;
public:
inline YBTSTransport()
: m_maxRead(0)
{}
~YBTSTransport()
{ resetTransport(); }
inline const DataBlock& readBuf() const
{ return m_readBuf; }
inline HANDLE detachRemote()
{ return m_remoteSocket.detach(); }
inline bool canSelect() const
{ return m_socket.canSelect(); }
protected:
bool send(const void* buf, unsigned int len, bool ignoreError = false);
inline bool send(const DataBlock& data, bool ignoreError = false)
{ return send(data.data(),data.length(),ignoreError); }
// Read socket data. Return 0: nothing read, >1: read data, negative: fatal error
int recv(bool ignoreError = false);
bool initTransport(bool stream, unsigned int buflen, bool reserveNull);
void resetTransport();
void alarmError(Socket& sock, const char* oper);
Socket m_socket;
Socket m_readSocket;
Socket m_writeSocket;
Socket m_remoteSocket;
DataBlock m_readBuf;
unsigned int m_maxRead;
};
class YBTSGlobalThread : public Thread, public GenObject
{
public:
inline YBTSGlobalThread(const char* name, Priority prio = Normal)
: Thread(name,prio)
{}
~YBTSGlobalThread()
{ set(this,false); }
inline void set(YBTSGlobalThread* th, bool add) {
if (!th)
return;
Lock lck(s_threadsMutex);
if (add)
s_threads.append(th)->setDelete(false);
else
s_threads.remove(th,false);
}
// Cancel all threads, wait to terminate if requested
// Return true if there are no running threads
static bool cancelAll(bool hard = false, unsigned int waitMs = 0);
static ObjList s_threads;
static Mutex s_threadsMutex;
};
class YBTSConnAuthThread : public YBTSGlobalThread, public YBTSConnAuthMt
{
public:
inline YBTSConnAuthThread(uint16_t connid, YBTSUE* ue, int origin)
: YBTSGlobalThread("YBTSConnAuth"), YBTSConnAuthMt(connid,ue,origin)
{}
~YBTSConnAuthThread()
{ notify(true); }
virtual void cleanup()
{ notify(true); }
protected:
virtual void run() {
set(this,true);
notify(false,authMt() == 0);
}
void notify(bool final, bool ok = false);
};
// Holds local area id
class YBTSLAI
{
public:
inline YBTSLAI(const char* lai = 0)
: m_lai(lai)
{}
YBTSLAI(const XmlElement& xml);
inline YBTSLAI(const YBTSLAI& other)
{ *this = other; }
inline const String& lai() const
{ return m_lai; }
inline const String& mccMnc() const
{ return m_mcc_mnc; }
inline void set(const char* mcc, const char* mnc, const char* lac) {
reset();
m_mcc_mnc << mcc << mnc;
m_lac = lac;
m_lai << m_mcc_mnc << "_" << m_lac;
}
inline void reset() {
m_mcc_mnc.clear();
m_lac.clear();
m_lai.clear();
}
XmlElement* build() const;
inline bool operator==(const YBTSLAI& other)
{ return m_lai == other.m_lai; }
inline bool operator!=(const YBTSLAI& other)
{ return m_lai != other.m_lai; }
inline const YBTSLAI& operator=(const YBTSLAI& other) {
m_mcc_mnc = other.m_mcc_mnc;
m_lac = other.m_lac;
m_lai = other.m_lai;
return *this;
}
protected:
String m_mcc_mnc; // Concatenated MCC + MNC
String m_lac; // LAC
String m_lai; // Concatenated mcc_mnc_lac
};
class YBTSTid : public RefObject
{
public:
enum Type {
Unknown = 0,
Sms,
Ussd,
};
inline YBTSTid(Type t, const String& callRef, bool incoming, uint8_t sapi,
const char* id = 0)
: m_ssId(id),
m_type(t), m_callRef(callRef), m_incoming(incoming), m_sapi(sapi),
m_timeout(0), m_pddTout(0), m_connId(-1), m_paging(false), m_cid(-1),
m_waiting(0)
{}
~YBTSTid();
inline const char* c_str() const
{ return m_ssId; }
inline const char* typeName() const
{ return typeName(m_type); }
// Wait for termination. Finalize if thread is cancelled
void wait();
// Finalize the session if waiting
void finalize(const char* localError, const char* cause = 0,
const String* facilityIE = 0);
// Set connection id, reset conn usage of old connection
// Increase conn usage on new connection if valid
void setConnId(int connId);
// Build SS message (Facility or Release Complete)
Message* ssMessage(bool facility);
// Retrieve next CID
inline int8_t nextCID() {
if (m_cid < 127)
return ++m_cid;
return (m_cid = 0);
}
virtual const String& toString() const
{ return m_ssId; }
static inline ObjList* findObj(ObjList& list, const String& callRef, bool incoming) {
for (ObjList* o = list.skipNull(); o; o = o->skipNext()) {
YBTSTid* i = static_cast<YBTSTid*>(o->get());
if (i->m_incoming == incoming && i->m_callRef == callRef)
return o;
}
return 0;
}
static inline YBTSTid* find(ObjList& list, const String& callRef, bool incoming) {
ObjList* o = findObj(list,callRef,incoming);
return o ? static_cast<YBTSTid*>(o->get()) : 0;
}
static inline YBTSTid* remove(ObjList& list, const String& callRef, bool incoming) {
ObjList* o = findObj(list,callRef,incoming);
return o ? static_cast<YBTSTid*>(o->remove(false)) : 0;
}
static inline YBTSTid* findMO(ObjList& list, const String& callRef)
{ return find(list,callRef,true); }
static inline const char* typeName(int t, const char* defVal = "unknown")
{ return lookup(t,s_typeName,defVal); }
static const TokenDict s_typeName[];
static Mutex s_mutex;
String m_ssId;
Type m_type;
String m_callRef; // TID: Call reference
bool m_incoming; // Transaction direction
uint8_t m_sapi; // SAPI to use
uint64_t m_timeout;
uint64_t m_pddTout;
int m_connId; // Connection id (less then 0: no connection)
RefPointer<YBTSUE> m_ue; // Used UE, may not be set
bool m_paging; // Paging the UE
String m_data; // Extra data
// SS specific data
String m_peerId; // SS session peer id
String m_startCID; // SS start component CID
int8_t m_cid; // Subsequent SS component CID
// Sync process
int m_waiting; // Waiting flag: don't auto terminate
String m_error; // Result: error string
String m_facility; // Result: facility IE
};
// A logical connection
// UE retrieve/set methods are not thread safe
class YBTSConn : public RefObject, public Mutex, public YBTSConnIdHolder
{
friend class YBTSSignalling;
friend class YBTSMM;
friend class YBTSDriver;
public:
enum Flags {
FNull = 0,
FLocUpd = 0x0001,
FMoCall = 0x0002,
FMoSms = 0x0004,
FMoUssd = 0x0008,
FCmSms = 0x0010,
FMtCall = 0x0200,
FMtSms = 0x0400,
FMtUssd = 0x0800,
FAskIMSI = 0x1000,
FAskIMEI = 0x2000,
};
~YBTSConn();
inline YBTSUE* ue()
{ return m_ue; }
inline YBTSSignalling* owner()
{ return m_owner; }
inline bool removed() const
{ return m_removed; }
inline bool hardRelease() const
{ return m_hardRelease; }
inline void hardRelease(bool hard)
{ m_hardRelease = hard; }
inline bool waitForTraffic() const
{ return m_waitForTraffic != 0; }
inline bool authenticated() const
{ return m_authenticated; }
inline void setAuthenticated()
{ m_authenticated = true; }
inline void setAuthenticated(int flag) {
if (0 != (m_authOrigin & flag))
m_authenticated = true;
}
inline void setEmergency()
{ m_emergency = true; }
inline int authSent(int flag)
{ return (m_authOrigin & flag); }
inline void setFlag(int mask)
{ m_flags |= mask; }
inline void resetFlag(int mask)
{ m_flags = m_flags & ~mask; }
inline int flag(int mask) const
{ return (m_flags & mask); }
inline void setFlagSafe(int mask) {
Lock lck(this);
setFlag(mask);
}
inline void resetFlagSafe(int mask) {
Lock lck(this);
resetFlag(mask);
}
// Peek at the pending XML element
inline const XmlElement* xml() const
{ return m_xml; }
// Take out the pending XML element
inline XmlElement* takeXml()
{ XmlElement* x = m_xml; m_xml = 0; return x; }
// Set pending XML. Consume given pointer
// Return false if another XML element is already pending
inline bool setXml(XmlElement* xml) {
if (!m_xml)
return ((m_xml = xml) != 0);
TelEngine::destruct(xml);
return false;
}
inline void getPhyInfo(String& info) {
Lock lck(this);
info = m_phyInfo;
}
inline void addPhyInfo(NamedList& msg) {
Lock lck(this);
msg.addParam("phy_info",m_phyInfo,false);
}
inline void setPhyInfo(const String& info) {
Lock lck(this);
m_phyInfo = info;
}
inline const String& extraRelease() const
{ return m_extraRelease; }
inline void extraRelease(const char* hexa)
{ if (hexa) m_extraRelease = hexa; }
inline int hoReference() const
{ return m_reference; }
inline bool isEmergency() const
{ return m_emergency; }
inline bool isCSFB() const
{ return m_csfb; }
inline bool hasSS()
{ return m_ss != 0; }
inline YBTSTid* takeSS() {
YBTSTid* ss = m_ss;
m_ss = 0;
return ss;
}
// Retrieve an SS TID
inline YBTSTid* findSSTid(const String& callRef, bool incoming) {
if (m_ss && m_ss->m_incoming == incoming && m_ss->m_callRef == callRef)
return m_ss;
return 0;
}
// Retrieve an SS TID
inline YBTSTid* findSSTid(const String& ssId) {
if (m_ss && ssId == m_ss->m_ssId)
return m_ss;
return 0;
}
// Take (remove) an SS TID
inline YBTSTid* takeSSTid(const String& callRef, bool incoming) {
if (m_ss && m_ss->m_incoming == incoming && m_ss->m_callRef == callRef)
return takeSS();
return 0;
}
// Take (remove) an SS TID
inline YBTSTid* takeSSTid(const String& ssId) {
if (m_ss && ssId == m_ss->m_ssId)
return takeSS();
return 0;
}
inline YBTSTid* getSSTid(const String& callRef, bool incoming, bool take)
{ return take ? takeSSTid(callRef,incoming) : findSSTid(callRef,incoming); }
inline YBTSTid* getSSTid(const String& ssId, bool take)
{ return take ? takeSSTid(ssId) : findSSTid(ssId); }
// Reset auth. Notify
inline void authEnd(bool ok, const char* error) {
if (m_auth)
m_auth->authEnd(ok,error);
resetAuth();
}
inline void authEnd(bool ok, XmlElement& xml) {
if (m_auth)
m_auth->authHandleRsp(ok,xml);
resetAuth();
}
inline void resetAuth() {
m_auth = 0;
m_authTout = 0;
}
// Partially deserialize and save GSM state
void saveGsmState(String& state);
// Restore saved GSM state and rebuild channel
void loadGsmState(RefPointer<YBTSChan>& chan, bool outgoing);
// Start media traffic. Return true is already started, false if requesting
bool startTraffic(uint8_t mode = 1);
// Handle media traffic start response
void startTrafficRsp(bool ok);
// Start SAPI (values 0..3).
// Return 0xff if start was sent (wait for establish) or requested SAPI
uint8_t startSapi(uint8_t sapi);
// Handle SAPI establish
void sapiEstablish(uint8_t sapi);
// Send an L3 connection related message
bool sendL3(XmlElement* xml, uint8_t info = 0);
// Check if the connection can be handed over
inline bool canHandover() const
{ return !(m_removed || m_xml || m_ss || m_auth || m_waitForTraffic); }
// Set the handover reference for this connection
inline void setHandover(uint8_t reference)
{ m_reference = reference; }
// Set CSFB flag
void setCSFB(const XmlElement* xml);
// Handle Handover Required
void gotHoRequired(const String& info);
// Serialize into a String
bool serialize(String& str);
protected:
YBTSConn(YBTSSignalling* owner, uint16_t connId);
// Set connection UE. Return false if requested to change an existing, different UE
bool setUE(YBTSUE* ue);
YBTSSignalling* m_owner;
bool m_removed; // Removed from owner
bool m_hardRelease; // Should hard release (after handover)
bool m_emergency; // Emergency SIMless connection
bool m_csfb; // Connection caused by CSFB
XmlElement* m_xml;
RefPointer<YBTSUE> m_ue;
ObjList m_sms; // Pending sms
YBTSTid* m_ss; // Pending non call related SS transaction
String m_extraRelease; // Extra octets for Channel Release
String m_phyInfo; // Latest physical channel information
String m_savedState; // GSM state prepared for Handover
uint8_t m_traffic; // Traffic channel available (mode)
uint8_t m_waitForTraffic; // Waiting for traffic to start
uint8_t m_sapiUp; // SAPI status: lower 4 bits SAPI + upper 4 bits if SAPI up on SDCCH
int m_reference; // Handover reference
// The following data is used by YBTSSignalling and protected by conns list mutex
uint64_t m_timeout; // Connection timeout
unsigned int m_usage; // Usage counter
int m_extTout; // Use extended conn timeout
int m_flags; // Conn flags
// Auth
YBTSConnAuth* m_auth;
uint64_t m_authTout;
bool m_authenticated; // Authenticated flag
int m_authOrigin; // Authentication sent at least once (flags)
};
// A GPRS logical connection
class YBTSGprsConn : public RefObject, public Mutex, public YBTSConnIdHolder
{
friend class YBTSSignalling;
friend class YBTSDriver;
public:
inline YBTSSignalling* owner()
{ return m_owner; }
bool send(YBTSMessage& msg) const;
bool send(BtsPrimitive prim, unsigned char info = 0) const;
void sendReject(unsigned char cause, BtsPrimitive prim = SigGprsAttachRej);
protected:
inline YBTSGprsConn(YBTSSignalling* owner, uint16_t connId)
: Mutex(false,"YBTSGprsConn"), YBTSConnIdHolder(connId),
m_owner(owner)
{ }
YBTSSignalling* m_owner;
};
class YBTSLog : public GenObject, public DebugEnabler, public Mutex,
public YBTSThreadOwner
{
public:
YBTSLog(const char* name);
inline YBTSTransport& transport()
{ return m_transport; }
bool start();
void stop();
// Read socket
virtual void processLoop();
bool setDebug(Message& msg, const String& target);
protected:
String m_name;
YBTSTransport m_transport;
};
class YBTSCommand : public GenObject, public DebugEnabler
{
public:
YBTSCommand();
bool send(const String& str, bool ignoreError = false);
bool recv(String& str, bool ignoreError = false);
bool sendRecv(String& str, bool ignoreError = false,
DebugEnabler* enabler = 0, int level = DebugAll);
inline bool sendRecv(const char* str, bool ignoreError = false,
DebugEnabler* enabler = 0, int level = DebugAll) {
String tmp(str);
return sendRecv(tmp,ignoreError,enabler,level);
}
inline YBTSTransport& transport()
{ return m_transport; }
bool start();
void stop();
bool setDebug(Message& msg, const String& target);
protected:
YBTSTransport m_transport;
};
class YBTSSignalling : public GenObject, public DebugEnabler, public Mutex,
public YBTSThreadOwner
{
friend class YBTSDriver;
public:
enum State {
Idle,
Started,
WaitHandshake,
Running,
Closing
};
enum Result {
Ok = 0,
Error = 1,
FatalError = 2
};
YBTSSignalling();
inline int state() const
{ return m_state; }
inline bool dumpData() const
{ return m_printMsg > 0; }
inline YBTSTransport& transport()
{ return m_transport; }
inline GSML3Codec& codec()
{ return m_codec; }
inline const YBTSLAI& lai() const
{ return m_lai; }
inline void waitHandshake() {
Lock lck(this);
changeState(WaitHandshake);
}
inline bool shouldCheckTimers()
{ return m_state == Running || m_state == WaitHandshake; }
int checkTimers(const Time& time = Time());
// Send a message
inline bool send(YBTSMessage& msg) {
Lock lck(this);
return sendInternal(msg);
}
// Send an L3 connection related message
inline bool sendL3Conn(uint16_t connId, XmlElement* xml, uint8_t info = 0) {
YBTSMessage m(SigL3Message,info,connId,xml);
return send(m);
}
// Send L3 RR Status
bool sendRRMStatus(uint16_t connId, uint8_t code);
// Send L3 SMS CP Data
bool sendSmsCPData(YBTSConn* conn, const String& callRef, bool tiFlag,
uint8_t sapi, const String& rpdu);
// Send L3 SMS CP Ack/Error
bool sendSmsCPRsp(YBTSConn* conn, const String& callRef, bool tiFlag,
uint8_t sapi, const char* cause = 0);
// Send L3 RP Ack/Error
bool sendSmsRPRsp(YBTSConn* conn, const String& callRef, bool tiFlag, uint8_t sapi,
uint8_t rpMsgRef, uint8_t cause);
// Send SS Facility or Release Complete
inline bool sendSS(bool facility, YBTSConn* conn, const String& callRef,
bool tiFlag, uint8_t sapi, const char* cause = 0, const char* facilityIE = 0) {
return conn && sendSS(facility,conn->connId(),callRef,tiFlag,sapi,
cause,facilityIE);
}
// Send SS Register
inline bool sendSSRegister(YBTSConn* conn, const String& callRef,
uint8_t sapi, const char* facility)
{ return conn && sendSSRegister(conn->connId(),callRef,sapi,facility); }
// Send auth request
// Return negative: no connection or failure, positive: auth request pending, 0: success
int authStart(YBTSConn* conn, YBTSConnAuth* auth, const String& rand,
const String& autn, const char* keySeq);
inline void handleAuthRsp(bool ok, YBTSConn* conn, XmlElement& xml) {
if (!conn)
return;
Lock lck(m_connsMutex);
conn->authEnd(ok,xml);
}
// Cancel connection authentication
inline void authCancel(YBTSConn* conn, YBTSConnAuth* auth) {
if (!auth)
return;
if (conn) {
Lock lck(m_connsMutex);
if (conn->m_auth == auth)
conn->resetAuth();
}
auth->m_authSent = false;
}
// Send auth reject
void authReject(YBTSConn* conn);
bool start();
void stop();
// Drop a connection
void dropConn(uint16_t connId, bool notifyPeer, uint8_t rrCause = 0);
inline void dropConn(YBTSConn* conn, bool notifyPeer, uint8_t rrCause = 0) {
if (conn)
dropConn(conn->connId(),notifyPeer,rrCause);
}
// Drop SS session
inline void dropSS(YBTSConn* conn, YBTSTid* tid, bool toMs, bool toNetwork,
const char* reason = 0)
{ dropSS(conn ? conn->connId() : NO_CONN_ID,tid,toMs && conn,toNetwork,reason); }
// Drop SS session
void dropAllSS(const char* reason = "net-out-of-order");
// Increase/decrease connection usage. Update its timeout
// Return false if connection is not found
inline bool setConnUsage(uint16_t connId, bool on, int flag = 0,
bool update = true) {
Lock lck(m_connsMutex);
YBTSConn* conn = findConnInternal(connId);
return conn && setConnUsageInternal(*conn,on,flag,update);
}
inline bool setConnUsage(YBTSConn* conn, bool on, int flag = 0,
bool update = true) {
if (!conn)
return false;
Lock lck(m_connsMutex);
return setConnUsageInternal(*conn,on,flag,update);
}
inline void setConnToutCheck(uint64_t tout) {
if (!tout)
return;
Lock lck(m_connsMutex);
setConnToutCheckInternal(tout);
}
// Add a pending MO sms info to a connection
// Increase connection usage counter on success
bool addMOSms(YBTSConn* conn, const String& callRef, uint8_t sapi,
uint8_t rpCallRef);
inline bool addMOSms(uint16_t connId, const String& callRef, uint8_t sapi,
uint8_t rpCallRef) {
RefPointer<YBTSConn> conn;
findConn(conn,connId,false);
return conn && addMOSms(conn,callRef,sapi,rpCallRef);
}
// Remove a pending sms info from a connection
// Decrease connection usage counter on success
YBTSSmsInfo* removeSms(YBTSConn* conn, const String& callRef, bool incoming);
// Respond to a MO SMS
bool moSmsRespond(YBTSConn* conn, const String& callRef, uint8_t cause,
const String* rpdu = 0);
inline bool moSmsRespond(uint16_t connId, const String& callRef, uint8_t cause,