summaryrefslogtreecommitdiffstats
path: root/chan_lcr.c
blob: 5c68e47880ba40a6048a4cc640547da9b5fcb5fe (plain) (blame)
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
-rw-r--r--Tex/Content/GSM.tex35
-rw-r--r--Tex/Images/used icons/3174 cluster contoller .jpgbin0 -> 12434 bytes
-rw-r--r--Tex/Images/used icons/bbfw media.jpgbin0 -> 26120 bytes
-rw-r--r--Tex/Images/used icons/bbfw.jpgbin0 -> 12800 bytes
-rw-r--r--Tex/Images/used icons/breakout box.jpgbin0 -> 17556 bytes
-rw-r--r--Tex/Images/used icons/cellular phone.jpgbin0 -> 22074 bytes
-rw-r--r--Tex/Images/used icons/class 4_5 switch.jpgbin0 -> 15627 bytes
-rw-r--r--Tex/Images/used icons/generic softswitch.jpgbin0 -> 14330 bytes
-rw-r--r--Tex/Images/used icons/hootphone.jpgbin0 -> 18828 bytes
-rw-r--r--Tex/Images/used icons/hp mini.jpgbin0 -> 17816 bytes
-rw-r--r--Tex/Images/used icons/ibm maniframe.jpgbin0 -> 15701 bytes
-rw-r--r--Tex/Images/used icons/ibm mini (as400).jpgbin0 -> 14561 bytes
-rw-r--r--Tex/Images/used icons/key.jpgbin0 -> 13222 bytes
-rw-r--r--Tex/Images/used icons/keys.jpgbin0 -> 24073 bytes
-rw-r--r--Tex/Images/used icons/laptop.jpgbin0 -> 21142 bytes
-rw-r--r--Tex/Images/used icons/mau.jpgbin0 -> 11871 bytes
-rw-r--r--Tex/Images/used icons/mini vax.jpgbin0 -> 14982 bytes
-rw-r--r--Tex/Images/used icons/modem.jpgbin0 -> 12658 bytes
-rw-r--r--Tex/Images/used icons/mux.jpgbin0 -> 18312 bytes
-rw-r--r--Tex/Images/used icons/radio tower.jpgbin0 -> 19444 bytes
-rw-r--r--Tex/Images/used icons/relational database.jpgbin0 -> 14094 bytes
-rw-r--r--Tex/Images/used icons/running man.jpgbin0 -> 20292 bytes
-rw-r--r--Tex/Images/used icons/satellite dish.jpgbin0 -> 18505 bytes
-rw-r--r--Tex/Images/used icons/sc2200_vsc3000host.jpgbin0 -> 18498 bytes
-rw-r--r--Tex/Images/used icons/storage array.jpgbin0 -> 20502 bytes
-rw-r--r--Tex/Images/used icons/terminal.jpgbin0 -> 19269 bytes
-rw-r--r--Tex/Master/Master.acn28
-rw-r--r--Tex/Master/Master.aux21
-rw-r--r--Tex/Master/Master.ist2
-rw-r--r--Tex/Master/Master.lof1
-rw-r--r--Tex/Master/Master.log169
-rw-r--r--Tex/Master/Master.pdfbin262852 -> 275215 bytes
-rw-r--r--Tex/Master/Master.synctex.gzbin245630 -> 252640 bytes
-rw-r--r--Tex/Master/Master.tex1
-rw-r--r--Tex/Master/Master.toc5
35 files changed, 170 insertions, 92 deletions
diff --git a/Tex/Content/GSM.tex b/Tex/Content/GSM.tex
index b35c36b..213f00f 100644
--- a/Tex/Content/GSM.tex
+++ b/Tex/Content/GSM.tex
@@ -91,6 +91,8 @@ The \gls{gsm} network is a distributed, star shaped network type that is built o
The telephony network is not only used to connect mobile subscribers to landline phones, but also to connect the different components of the mobile network.
The main components of a \gls{gsm} network can be seen in figure \ref{fig:gsm_network} as well as the interfaces that are used to connect them.
\begin{figure}
+\centering
+\includegraphics{../Images/template}
\caption{The main components of a GSM network.}
\label{fig:gsm_network}
\end{figure}
@@ -797,9 +799,40 @@ Therefore in a strict sense \gls{mm} and \gls{cc} information does not belong to
\section{IMSI-Catcher}
\label{sec:catcher}
+
+An \gls{imsi}-Catcher is a technical device that is used to capture \gls{imsi} and \gls{imei} numbers of mobile subscribers.
+The knowledge of the \gls{imsi} and \gls{imei} numbers can be exploited to either tap into calls the particular participant is doing or pinpoint the location of the subscriber \cite{fox}.
+
+This topic came up in conjunction with crime fighting and prevention with the advent of mobile telephones.
+A mobile phone cannot be tapped in the same way as a landline phone since the subscriber can change places and also phones.
+This has proven to be a challenge to the authorities.
+
+In 1996 Rohde \& Schwarz a company based in Munich, Germany has developed a device called ''GA 090'' which was the first \gls{imsi}-Catcher.
+Its was capable of yielding a list with all the \gls{imsi} number is the perimeter as well as pinpointing the location of a subscriber given the \gls{imsi}.
+Short thereafter the ''GA 900'' was presented which had the additional capabilities of tapping into calls that originated from a particular \gls{imsi}.
+These commercial versions of catchers produced by Rohde \& Schwarz are priced between 200 000 \euro{} and 300 000 \euro{} \cite{fox}.
+Although these catchers are meant to be bought by authorities, it is also possible to buy them as a private customer or to order them from abroad.
+Regulations prohibit the use of \gls{imsi}-Catchers for individuals since the frequency bands the \gls{gsm} network uses are reserved for providers.
+However, it cannot be guaranteed that such a catcher is not used illegally.
+In addition to these commercial products different projects \cite{dennis, ccc_catcher} have shown that such a device can be built at a very low budget.
+This only intensifies risk that is imposed by the abusive usage of such an instrument.
+Figure \ref{fig:catchers} shows the ''GA 900'' side by side with a self built catcher.
+\begin{figure}
+\centering
+\caption{The ''GA 900'' and a self build IMSI-Catcher.}
+\label{fig:catchers}
+\end{figure}
+
+Section \ref{sec:catcher_operation} will show how an \gls{imsi}-Catcher works and how subscribers can be caught.
+In addition the potency of these attacks will be evaluated and what risks these impose from a technical perspective.
+The next section will explain when a catcher can be used in Germany from a legal perspective and show that this handling imposes a privacy risk on citizens.
+
\subsection{Mode of Operation}
-\subsection{Possible Attacks}
+\label{sec:catcher_operation}
+
\subsection{Law Situation in Germany}
+\label{sec:catcher_law}
+
%germany not plagued by terrorism
%response to 9/11: overreaction (Luftschutzgesetz)
%no definition for terror in german law
diff --git a/Tex/Images/used icons/3174 cluster contoller .jpg b/Tex/Images/used icons/3174 cluster contoller .jpg
new file mode 100644
index 0000000..e4a3deb
--- /dev/null
+++ b/Tex/Images/used icons/3174 cluster contoller .jpg
Binary files differ
diff --git a/Tex/Images/used icons/bbfw media.jpg b/Tex/Images/used icons/bbfw media.jpg
new file mode 100644
index 0000000..385aa34
--- /dev/null
+++ b/Tex/Images/used icons/bbfw media.jpg
Binary files differ
diff --git a/Tex/Images/used icons/bbfw.jpg b/Tex/Images/used icons/bbfw.jpg
new file mode 100644
index 0000000..72f2699
--- /dev/null
+++ b/Tex/Images/used icons/bbfw.jpg
Binary files differ
diff --git a/Tex/Images/used icons/breakout box.jpg b/Tex/Images/used icons/breakout box.jpg
new file mode 100644
index 0000000..e80b6d1
--- /dev/null
+++ b/Tex/Images/used icons/breakout box.jpg
Binary files differ
diff --git a/Tex/Images/used icons/cellular phone.jpg b/Tex/Images/used icons/cellular phone.jpg
new file mode 100644
index 0000000..0f8c948
--- /dev/null
+++ b/Tex/Images/used icons/cellular phone.jpg
Binary files differ
diff --git a/Tex/Images/used icons/class 4_5 switch.jpg b/Tex/Images/used icons/class 4_5 switch.jpg
new file mode 100644
index 0000000..2731d24
--- /dev/null
+++ b/Tex/Images/used icons/class 4_5 switch.jpg
Binary files differ
diff --git a/Tex/Images/used icons/generic softswitch.jpg b/Tex/Images/used icons/generic softswitch.jpg
new file mode 100644
index 0000000..8f01b0f
--- /dev/null
+++ b/Tex/Images/used icons/generic softswitch.jpg
Binary files differ
diff --git a/Tex/Images/used icons/hootphone.jpg b/Tex/Images/used icons/hootphone.jpg
new file mode 100644
index 0000000..11bdfe2
--- /dev/null
+++ b/Tex/Images/used icons/hootphone.jpg
Binary files differ
diff --git a/Tex/Images/used icons/hp mini.jpg b/Tex/Images/used icons/hp mini.jpg
new file mode 100644
index 0000000..3810a0b
--- /dev/null
+++ b/Tex/Images/used icons/hp mini.jpg
Binary files differ
diff --git a/Tex/Images/used icons/ibm maniframe.jpg b/Tex/Images/used icons/ibm maniframe.jpg
new file mode 100644
index 0000000..ed9b31b
--- /dev/null
+++ b/Tex/Images/used icons/ibm maniframe.jpg
Binary files differ
diff --git a/Tex/Images/used icons/ibm mini (as400).jpg b/Tex/Images/used icons/ibm mini (as400).jpg
new file mode 100644
index 0000000..cd74e50
--- /dev/null
+++ b/Tex/Images/used icons/ibm mini (as400).jpg
Binary files differ
diff --git a/Tex/Images/used icons/key.jpg b/Tex/Images/used icons/key.jpg
new file mode 100644
index 0000000..0643cdf
--- /dev/null
+++ b/Tex/Images/used icons/key.jpg
Binary files differ
diff --git a/Tex/Images/used icons/keys.jpg b/Tex/Images/used icons/keys.jpg
new file mode 100644
index 0000000..0c4f99f
--- /dev/null
+++ b/Tex/Images/used icons/keys.jpg
Binary files differ
diff --git a/Tex/Images/used icons/laptop.jpg b/Tex/Images/used icons/laptop.jpg
new file mode 100644
index 0000000..3d50fcd
--- /dev/null
+++ b/Tex/Images/used icons/laptop.jpg
Binary files differ
diff --git a/Tex/Images/used icons/mau.jpg b/Tex/Images/used icons/mau.jpg
new file mode 100644
index 0000000..06737c9
--- /dev/null
+++ b/Tex/Images/used icons/mau.jpg
Binary files differ
diff --git a/Tex/Images/used icons/mini vax.jpg b/Tex/Images/used icons/mini vax.jpg
new file mode 100644
index 0000000..984ba6d
--- /dev/null
+++ b/Tex/Images/used icons/mini vax.jpg
Binary files differ
diff --git a/Tex/Images/used icons/modem.jpg b/Tex/Images/used icons/modem.jpg
new file mode 100644
index 0000000..32dd13c
--- /dev/null
+++ b/Tex/Images/used icons/modem.jpg
Binary files differ
diff --git a/Tex/Images/used icons/mux.jpg b/Tex/Images/used icons/mux.jpg
new file mode 100644
index 0000000..a00e235
--- /dev/null
+++ b/Tex/Images/used icons/mux.jpg
Binary files differ
diff --git a/Tex/Images/used icons/radio tower.jpg b/Tex/Images/used icons/radio tower.jpg
new file mode 100644
index 0000000..9b11b5b
--- /dev/null
+++ b/Tex/Images/used icons/radio tower.jpg
Binary files differ
diff --git a/Tex/Images/used icons/relational database.jpg b/Tex/Images/used icons/relational database.jpg
new file mode 100644
index 0000000..672f9d0
--- /dev/null
+++ b/Tex/Images/used icons/relational database.jpg
Binary files differ
diff --git a/Tex/Images/used icons/running man.jpg b/Tex/Images/used icons/running man.jpg
new file mode 100644
index 0000000..74e6415
--- /dev/null
+++ b/Tex/Images/used icons/running man.jpg
Binary files differ
diff --git a/Tex/Images/used icons/satellite dish.jpg b/Tex/Images/used icons/satellite dish.jpg
new file mode 100644
index 0000000..c259d51
--- /dev/null
+++ b/Tex/Images/used icons/satellite dish.jpg
Binary files differ
diff --git a/Tex/Images/used icons/sc2200_vsc3000host.jpg b/Tex/Images/used icons/sc2200_vsc3000host.jpg
new file mode 100644
index 0000000..a852340
--- /dev/null
+++ b/Tex/Images/used icons/sc2200_vsc3000host.jpg
Binary files differ
diff --git a/Tex/Images/used icons/storage array.jpg b/Tex/Images/used icons/storage array.jpg
new file mode 100644
index 0000000..a8ed8d8
--- /dev/null
+++ b/Tex/Images/used icons/storage array.jpg
Binary files differ
diff --git a/Tex/Images/used icons/terminal.jpg b/Tex/Images/used icons/terminal.jpg
new file mode 100644
index 0000000..fe6fc91
--- /dev/null
+++ b/Tex/Images/used icons/terminal.jpg
Binary files differ
diff --git a/Tex/Master/Master.acn b/Tex/Master/Master.acn
index 6fcce43..3f42794 100644
--- a/Tex/Master/Master.acn
+++ b/Tex/Master/Master.acn
@@ -37,7 +37,7 @@
\glossaryentry{GSM?\glossaryentryfield{gsm}{\glsnamefont{GSM}}{Global System for Mobile Communications}{\relax }|setentrycounter{page}\glsnumberformat}{5}
\glossaryentry{BSS?\glossaryentryfield{bss}{\glsnamefont{BSS}}{Basestation Subsystem}{\relax }|setentrycounter{page}\glsnumberformat}{5}
\glossaryentry{MS?\glossaryentryfield{ms}{\glsnamefont{MS}}{Mobile Station}{\relax }|setentrycounter{page}\glsnumberformat}{5}
-\glossaryentry{NSS?\glossaryentryfield{nss}{\glsnamefont{NSS}}{Network Subsystem}{\relax }|setentrycounter{page}\glsnumberformat}{5}
+\glossaryentry{NSS?\glossaryentryfield{nss}{\glsnamefont{NSS}}{Network Subsystem}{\relax }|setentrycounter{page}\glsnumberformat}{6}
\glossaryentry{PSTN?\glossaryentryfield{pstn}{\glsnamefont{PSTN}}{Public Standard Telephone Network}{\relax }|setentrycounter{page}\glsnumberformat}{6}
\glossaryentry{IN?\glossaryentryfield{in}{\glsnamefont{IN}}{Intelligent Network Subsystem}{\relax }|setentrycounter{page}\glsnumberformat}{6}
\glossaryentry{VAS?\glossaryentryfield{vas}{\glsnamefont{VAS}}{value-added service}{\relax }|setentrycounter{page}\glsnumberformat}{6}
@@ -57,8 +57,8 @@
\glossaryentry{SMS?\glossaryentryfield{sms}{\glsnamefont{SMS}}{Short Message Service}{\relax }|setentrycounter{page}\glsnumberformat}{6}
\glossaryentry{PLMS?\glossaryentryfield{plmn}{\glsnamefont{PLMS}}{Public Land Mobile Network}{\relax }|setentrycounter{page}\glsnumberformat}{6}
\glossaryentry{SIM?\glossaryentryfield{sim}{\glsnamefont{SIM}}{Subscriber Identity Module}{\relax }|setentrycounter{page}\glsnumberformat}{6}
-\glossaryentry{IMEI?\glossaryentryfield{imei}{\glsnamefont{IMEI}}{International Mobile Equipment Identifier}{\relax }|setentrycounter{page}\glsnumberformat}{6}
-\glossaryentry{IMEI?\glossaryentryfield{imei}{\glsnamefont{IMEI}}{International Mobile Equipment Identifier}{\relax }|setentrycounter{page}\glsnumberformat}{6}
+\glossaryentry{IMEI?\glossaryentryfield{imei}{\glsnamefont{IMEI}}{International Mobile Equipment Identifier}{\relax }|setentrycounter{page}\glsnumberformat}{7}
+\glossaryentry{IMEI?\glossaryentryfield{imei}{\glsnamefont{IMEI}}{International Mobile Equipment Identifier}{\relax }|setentrycounter{page}\glsnumberformat}{7}
\glossaryentry{PDA?\glossaryentryfield{pda}{\glsnamefont{PDA}}{Personal Digital Assistant}{\relax }|setentrycounter{page}\glsnumberformat}{7}
\glossaryentry{ME?\glossaryentryfield{me}{\glsnamefont{ME}}{Mobile Equipment}{\relax }|setentrycounter{page}\glsnumberformat}{7}
\glossaryentry{ME?\glossaryentryfield{me}{\glsnamefont{ME}}{Mobile Equipment}{\relax }|setentrycounter{page}\glsnumberformat}{7}
@@ -96,8 +96,8 @@
\glossaryentry{MSC?\glossaryentryfield{msc}{\glsnamefont{MSC}}{Mobile Switching Center}{\relax }|setentrycounter{page}\glsnumberformat}{8}
\glossaryentry{MSC?\glossaryentryfield{msc}{\glsnamefont{MSC}}{Mobile Switching Center}{\relax }|setentrycounter{page}\glsnumberformat}{8}
\glossaryentry{PSTN?\glossaryentryfield{pstn}{\glsnamefont{PSTN}}{Public Standard Telephone Network}{\relax }|setentrycounter{page}\glsnumberformat}{8}
-\glossaryentry{NSS?\glossaryentryfield{nss}{\glsnamefont{NSS}}{Network Subsystem}{\relax }|setentrycounter{page}\glsnumberformat}{8}
-\glossaryentry{HLR?\glossaryentryfield{hlr}{\glsnamefont{HLR}}{Home Location Register}{\relax }|setentrycounter{page}\glsnumberformat}{8}
+\glossaryentry{NSS?\glossaryentryfield{nss}{\glsnamefont{NSS}}{Network Subsystem}{\relax }|setentrycounter{page}\glsnumberformat}{9}
+\glossaryentry{HLR?\glossaryentryfield{hlr}{\glsnamefont{HLR}}{Home Location Register}{\relax }|setentrycounter{page}\glsnumberformat}{9}
\glossaryentry{VLR?\glossaryentryfield{vlr}{\glsnamefont{VLR}}{Visitor Location Register}{\relax }|setentrycounter{page}\glsnumberformat}{9}
\glossaryentry{EIR?\glossaryentryfield{eir}{\glsnamefont{EIR}}{Equipment Identity Register}{\relax }|setentrycounter{page}\glsnumberformat}{9}
\glossaryentry{AC?\glossaryentryfield{ac}{\glsnamefont{AC}}{Authentication Center}{\relax }|setentrycounter{page}\glsnumberformat}{9}
@@ -116,11 +116,11 @@
\glossaryentry{MSC?\glossaryentryfield{msc}{\glsnamefont{MSC}}{Mobile Switching Center}{\relax }|setentrycounter{page}\glsnumberformat}{9}
\glossaryentry{MM?\glossaryentryfield{mm}{\glsnamefont{MM}}{Mobility Management}{\relax }|setentrycounter{page}\glsnumberformat}{9}
\glossaryentry{MSC?\glossaryentryfield{msc}{\glsnamefont{MSC}}{Mobile Switching Center}{\relax }|setentrycounter{page}\glsnumberformat}{9}
-\glossaryentry{MSC?\glossaryentryfield{msc}{\glsnamefont{MSC}}{Mobile Switching Center}{\relax }|setentrycounter{page}\glsnumberformat}{9}
+\glossaryentry{MSC?\glossaryentryfield{msc}{\glsnamefont{MSC}}{Mobile Switching Center}{\relax }|setentrycounter{page}\glsnumberformat}{10}
\glossaryentry{NSS?\glossaryentryfield{nss}{\glsnamefont{NSS}}{Network Subsystem}{\relax }|setentrycounter{page}\glsnumberformat}{10}
\glossaryentry{HLR?\glossaryentryfield{hlr}{\glsnamefont{HLR}}{Home Location Register}{\relax }|setentrycounter{page}\glsnumberformat}{10}
-\glossaryentry{IMSI?\glossaryentryfield{imsi}{\glsnamefont{IMSI}}{International Mobile Subscriber Identification}{\relax }|setentrycounter{page}\glsnumberformat}{10}
-\glossaryentry{MSISDN?\glossaryentryfield{msisdn}{\glsnamefont{MSISDN}}{Mobile Subscriber Integrated Services Digital Network Number}{\relax }|setentrycounter{page}\glsnumberformat}{10}
+\glossaryentry{IMSI?\glossaryentryfield{imsi}{\glsnamefont{IMSI}}{International Mobile Subscriber Identification}{\relax }|setentrycounter{page}\glsnumberformat}{11}
+\glossaryentry{MSISDN?\glossaryentryfield{msisdn}{\glsnamefont{MSISDN}}{Mobile Subscriber Integrated Services Digital Network Number}{\relax }|setentrycounter{page}\glsnumberformat}{11}
\glossaryentry{IMSI?\glossaryentryfield{imsi}{\glsnamefont{IMSI}}{International Mobile Subscriber Identification}{\relax }|setentrycounter{page}\glsnumberformat}{11}
\glossaryentry{HLR?\glossaryentryfield{hlr}{\glsnamefont{HLR}}{Home Location Register}{\relax }|setentrycounter{page}\glsnumberformat}{11}
\glossaryentry{VLR?\glossaryentryfield{vlr}{\glsnamefont{VLR}}{Visitor Location Register}{\relax }|setentrycounter{page}\glsnumberformat}{11}
@@ -379,3 +379,15 @@
\glossaryentry{RR?\glossaryentryfield{rr}{\glsnamefont{RR}}{Radio Resource}{\relax }|setentrycounter{page}\glsnumberformat}{25}
\glossaryentry{MS?\glossaryentryfield{ms}{\glsnamefont{MS}}{Mobile Station}{\relax }|setentrycounter{page}\glsnumberformat}{25}
\glossaryentry{NSS?\glossaryentryfield{nss}{\glsnamefont{NSS}}{Network Subsystem}{\relax }|setentrycounter{page}\glsnumberformat}{25}
+\glossaryentry{IMSI?\glossaryentryfield{imsi}{\glsnamefont{IMSI}}{International Mobile Subscriber Identification}{\relax }|setentrycounter{page}\glsnumberformat}{25}
+\glossaryentry{IMSI?\glossaryentryfield{imsi}{\glsnamefont{IMSI}}{International Mobile Subscriber Identification}{\relax }|setentrycounter{page}\glsnumberformat}{25}
+\glossaryentry{IMEI?\glossaryentryfield{imei}{\glsnamefont{IMEI}}{International Mobile Equipment Identifier}{\relax }|setentrycounter{page}\glsnumberformat}{25}
+\glossaryentry{IMSI?\glossaryentryfield{imsi}{\glsnamefont{IMSI}}{International Mobile Subscriber Identification}{\relax }|setentrycounter{page}\glsnumberformat}{25}
+\glossaryentry{IMEI?\glossaryentryfield{imei}{\glsnamefont{IMEI}}{International Mobile Equipment Identifier}{\relax }|setentrycounter{page}\glsnumberformat}{25}
+\glossaryentry{IMSI?\glossaryentryfield{imsi}{\glsnamefont{IMSI}}{International Mobile Subscriber Identification}{\relax }|setentrycounter{page}\glsnumberformat}{25}
+\glossaryentry{IMSI?\glossaryentryfield{imsi}{\glsnamefont{IMSI}}{International Mobile Subscriber Identification}{\relax }|setentrycounter{page}\glsnumberformat}{25}
+\glossaryentry{IMSI?\glossaryentryfield{imsi}{\glsnamefont{IMSI}}{International Mobile Subscriber Identification}{\relax }|setentrycounter{page}\glsnumberformat}{25}
+\glossaryentry{IMSI?\glossaryentryfield{imsi}{\glsnamefont{IMSI}}{International Mobile Subscriber Identification}{\relax }|setentrycounter{page}\glsnumberformat}{25}
+\glossaryentry{IMSI?\glossaryentryfield{imsi}{\glsnamefont{IMSI}}{International Mobile Subscriber Identification}{\relax }|setentrycounter{page}\glsnumberformat}{25}
+\glossaryentry{GSM?\glossaryentryfield{gsm}{\glsnamefont{GSM}}{Global System for Mobile Communications}{\relax }|setentrycounter{page}\glsnumberformat}{25}
+\glossaryentry{IMSI?\glossaryentryfield{imsi}{\glsnamefont{IMSI}}{International Mobile Subscriber Identification}{\relax }|setentrycounter{page}\glsnumberformat}{26}
diff --git a/Tex/Master/Master.aux b/Tex/Master/Master.aux
index ac42529..cbf70c1 100644
--- a/Tex/Master/Master.aux
+++ b/Tex/Master/Master.aux
@@ -85,10 +85,10 @@
\citation{protocols1999}
\citation{protocols1999}
\citation{kommsys2006}
-\citation{GSM23003}
-\citation{ITU212}
\FN@pp@footnote@aux{3}{7}
\FN@pp@footnote@aux{4}{7}
+\citation{GSM23003}
+\citation{ITU212}
\@writefile{lot}{\contentsline {table}{\numberline {2.1}{\ignorespaces Subset of data stored on a SIM card. Adopted from \cite {protocols1999}}}{8}}
\newlabel{tab:simdata}{{2.1}{8}}
\@writefile{toc}{\contentsline {subsection}{\numberline {2.2.2}Network Subsystem}{8}}
@@ -183,14 +183,19 @@
\@writefile{toc}{\contentsline {paragraph}{Physical Layer (Layer 1):}{24}}
\@writefile{toc}{\contentsline {paragraph}{Data Link (Layer 2):}{24}}
\citation{protocols1999}
+\citation{fox}
+\citation{fox}
+\citation{dennis}
+\citation{ccc_catcher}
\@writefile{toc}{\contentsline {paragraph}{Network (Layer 3):}{25}}
\@writefile{toc}{\contentsline {section}{\numberline {2.4}IMSI-Catcher}{25}}
\newlabel{sec:catcher}{{2.4}{25}}
-\@writefile{toc}{\contentsline {subsection}{\numberline {2.4.1}Mode of Operation}{25}}
-\@writefile{toc}{\contentsline {subsection}{\numberline {2.4.2}Possible Attacks}{25}}
-\@writefile{toc}{\contentsline {subsection}{\numberline {2.4.3}Law Situation in Germany}{25}}
-\FN@pp@footnotehinttrue
-\FN@pp@footnotehinttrue
+\@writefile{lof}{\contentsline {figure}{\numberline {2.13}{\ignorespaces The ''GA 900'' and a self build IMSI-Catcher.}}{26}}
+\newlabel{fig:catchers}{{2.13}{26}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {2.4.1}Mode of Operation}{26}}
+\newlabel{sec:catcher_operation}{{2.4.1}{26}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {2.4.2}Law Situation in Germany}{26}}
+\newlabel{sec:catcher_law}{{2.4.2}{26}}
\FN@pp@footnotehinttrue
\bibstyle{acm}
\citation{*}
@@ -209,6 +214,8 @@
\bibcite{protocols1999}{12}
\FN@pp@footnotehinttrue
\FN@pp@footnotehinttrue
+\FN@pp@footnotehinttrue
+\FN@pp@footnotehinttrue
\@writefile{toc}{\contentsline {chapter}{Bibliography}{I}}
\bibcite{hsdpa}{13}
\bibcite{hsupa}{14}
diff --git a/Tex/Master/Master.ist b/Tex/Master/Master.ist
index 9210594..717b09e 100644
--- a/Tex/Master/Master.ist
+++ b/Tex/Master/Master.ist
@@ -1,5 +1,5 @@
% makeindex style file created by the glossaries package
-% for document 'Master' on 2012-2-10
+% for document 'Master' on 2012-2-13
actual '?'
encap '|'
level '!'
diff --git a/Tex/Master/Master.lof b/Tex/Master/Master.lof
index cc337f7..6d11d21 100644
--- a/Tex/Master/Master.lof
+++ b/Tex/Master/Master.lof
@@ -13,3 +13,4 @@
\contentsline {figure}{\numberline {2.10}{\ignorespaces Structural Comparison of different Burst types. After \cite {GSM2009}.}}{20}
\contentsline {figure}{\numberline {2.11}{\ignorespaces Example mapping of logical channels. After \cite {protocols1999}.}}{22}
\contentsline {figure}{\numberline {2.12}{\ignorespaces Example of Multiframe-configurations for a base station \cite {kommsys2006}.}}{23}
+\contentsline {figure}{\numberline {2.13}{\ignorespaces The ''GA 900'' and a self build IMSI-Catcher.}}{26}
diff --git a/Tex/Master/Master.log b/Tex/Master/Master.log
index 28e1f4e..e2dd2c5 100644
--- a/Tex/Master/Master.log
+++ b/Tex/Master/Master.log
@@ -1,4 +1,4 @@
-This is pdfTeX, Version 3.1415926-1.40.10 (TeX Live 2009/Debian) (format=pdflatex 2012.1.7) 10 FEB 2012 18:09
+This is pdfTeX, Version 3.1415926-1.40.10 (TeX Live 2009/Debian) (format=pdflatex 2012.1.7) 13 FEB 2012 18:03
entering extended mode
%&-line parsing enabled.
**Master.tex
@@ -127,7 +127,11 @@ basics and keyval usage)'
\c@titlepage=\count89
\titlebox=\box27
-) (/usr/share/texmf-texlive/tex/latex/appendix/appendix.sty
+) (/usr/share/texmf-texlive/tex/latex/eurosym/eurosym.sty
+Package: eurosym 1998/08/06 v1.1 European currency symbol ``Euro''
+\@eurobox=\box28
+)
+(/usr/share/texmf-texlive/tex/latex/appendix/appendix.sty
Package: appendix 2009/09/02 v1.2b extra appendix facilities
\c@@pps=\count90
\c@@ppsavesec=\count91
@@ -245,8 +249,8 @@ LaTeX Info: Redefining \overline on input line 307.
LaTeX Info: Redefining \ldots on input line 379.
LaTeX Info: Redefining \dots on input line 382.
LaTeX Info: Redefining \cdots on input line 467.
-\Mathstrutbox@=\box28
-\strutbox@=\box29
+\Mathstrutbox@=\box29
+\strutbox@=\box30
\big@size=\dimen108
LaTeX Font Info: Redeclaring font encoding OML on input line 567.
LaTeX Font Info: Redeclaring font encoding OMS on input line 568.
@@ -344,7 +348,7 @@ File: epstopdf-sys.cfg 2009/10/26 v1.1 Configuration of epstopdf for TeX Live
)))
(/usr/share/texmf-texlive/tex/latex/listings/listings.sty
\lst@mode=\count109
-\lst@gtempboxa=\box30
+\lst@gtempboxa=\box31
\lst@token=\toks28
\lst@length=\count110
\lst@currlwidth=\dimen117
@@ -360,7 +364,7 @@ File: epstopdf-sys.cfg 2009/10/26 v1.1 Configuration of epstopdf for TeX Live
File: lstmisc.sty 2007/02/22 1.4 (Carsten Heinz)
\c@lstnumber=\count115
\lst@skipnumbers=\count116
-\lst@framebox=\box31
+\lst@framebox=\box32
)
(/usr/share/texmf-texlive/tex/latex/listings/listings.cfg
File: listings.cfg 2007/02/22 1.4 listings configuration
@@ -466,10 +470,10 @@ Package: longtable 2004/02/01 v4.11 Multi-page Table package (DPC)
\LTpost=\skip58
\LTchunksize=\count124
\LTcapwidth=\dimen122
-\LT@head=\box32
-\LT@firsthead=\box33
-\LT@foot=\box34
-\LT@lastfoot=\box35
+\LT@head=\box33
+\LT@firsthead=\box34
+\LT@foot=\box35
+\LT@lastfoot=\box36
\LT@cols=\count125
\LT@rows=\count126
\c@LT@tables=\count127
@@ -500,7 +504,7 @@ Package: supertabular 2004/02/20 v4.1e the supertabular environment
\ST@prevht=\dimen131
\ST@toadd=\dimen132
\ST@dimen=\dimen133
-\ST@pbox=\box36
+\ST@pbox=\box37
))
(/usr/share/texmf-texlive/tex/latex/glossaries/styles/glossary-tree.sty
Package: glossary-tree 2009/01/14 v1.01 (NLCT)
@@ -517,8 +521,8 @@ Package: pstricks 2008/11/26 v0.40 LaTeX wrapper for `PSTricks' (RN,HV)
\pst@dimd=\dimen137
\pst@dimg=\dimen138
\pst@dimh=\dimen139
-\pst@hbox=\box37
-\pst@boxg=\box38
+\pst@hbox=\box38
+\pst@boxg=\box39
\pst@cnta=\count130
\pst@cntb=\count131
\pst@cntc=\count132
@@ -537,7 +541,7 @@ Package: pstricks 2008/11/26 v0.40 LaTeX wrapper for `PSTricks' (RN,HV)
\psframesep=\dimen145
\pslabelsep=\dimen146
\pst@shift=\dimen147
-\theoverlaybox=\box39
+\theoverlaybox=\box40
)
File: pstricks.tex 2009/05/19 v1.29 `PSTricks' (tvz,hv)
)
@@ -556,7 +560,7 @@ Package: pgfplots 2009/02/14 Version 1.2.2
\pgfutil@everybye=\toks38
)
(/usr/share/texmf/tex/generic/pgf/utilities/pgfutil-latex.def
-\pgfutil@abb=\box40
+\pgfutil@abb=\box41
(/usr/share/texmf-texlive/tex/latex/ms/everyshi.sty
Package: everyshi 2001/05/15 v3.00 EveryShipout Package (MS)
@@ -621,7 +625,7 @@ Package: pgfcore 2010/04/11 v2.10 (rcs-revision 1.7)
(/usr/share/texmf/tex/generic/pgf/math/pgfmathparser.code.tex
\pgfmath@dimen=\dimen156
\pgfmath@count=\count143
-\pgfmath@box=\box41
+\pgfmath@box=\box42
\pgfmath@toks=\toks42
\pgfmath@stack@operand=\toks43
\pgfmath@stack@operation=\toks44
@@ -666,9 +670,9 @@ File: pgfcorepathusage.code.tex 2008/04/22 (rcs-revision 1.12)
)
(/usr/share/texmf/tex/generic/pgf/basiclayer/pgfcorescopes.code.tex
File: pgfcorescopes.code.tex 2010/09/08 (rcs-revision 1.34)
-\pgfpic=\box42
-\pgf@hbox=\box43
-\pgf@layerbox@main=\box44
+\pgfpic=\box43
+\pgf@hbox=\box44
+\pgf@layerbox@main=\box45
\pgf@picture@serial@count=\count145
)
(/usr/share/texmf/tex/generic/pgf/basiclayer/pgfcoregraphicstate.code.tex
@@ -703,7 +707,7 @@ File: pgfcoreimage.code.tex 2010/03/25 (rcs-revision 1.16)
(/usr/share/texmf/tex/generic/pgf/basiclayer/pgfcoreexternal.code.tex
File: pgfcoreexternal.code.tex 2010/09/01 (rcs-revision 1.17)
-\pgfexternal@startupbox=\box45
+\pgfexternal@startupbox=\box46
))
(/usr/share/texmf/tex/generic/pgf/basiclayer/pgfcorelayers.code.tex
File: pgfcorelayers.code.tex 2010/08/27 (rcs-revision 1.2)
@@ -716,7 +720,7 @@ File: pgfcorepatterns.code.tex 2009/07/02 (rcs-revision 1.3)
)))
(/usr/share/texmf/tex/generic/pgf/modules/pgfmoduleshapes.code.tex
File: pgfmoduleshapes.code.tex 2010/09/09 (rcs-revision 1.13)
-\pgfnodeparttextbox=\box46
+\pgfnodeparttextbox=\box47
)
(/usr/share/texmf/tex/generic/pgf/modules/pgfmoduleplot.code.tex
File: pgfmoduleplot.code.tex 2010/10/22 (rcs-revision 1.8)
@@ -753,8 +757,8 @@ File: pgflibraryplothandlers.code.tex 2010/05/31 v2.10 (rcs-revision 1.15)
\tikz@lastysaved=\dimen188
\tikzleveldistance=\dimen189
\tikzsiblingdistance=\dimen190
-\tikz@figbox=\box47
-\tikz@tempbox=\box48
+\tikz@figbox=\box48
+\tikz@tempbox=\box49
\tikztreelevel=\count148
\tikznumberofchildren=\count149
\tikznumberofcurrentchild=\count150
@@ -831,7 +835,7 @@ ations.code.tex
\pgfdecorationsegmentamplitude=\dimen198
\pgfdecorationsegmentlength=\dimen199
)
-\tikz@lib@dec@box=\box49
+\tikz@lib@dec@box=\box50
)
(/usr/share/texmf/tex/generic/pgf/frontendlayer/tikz/libraries/tikzlibrarydecor
ations.pathmorphing.code.tex
@@ -911,35 +915,35 @@ File: lstlang1.sty 2004/09/05 1.3 listings language file
\glo@main@file=\write6
\openout6 = `Master.glo'.
-Package glossaries Info: Writing glossary file Master.glo on input line 93.
+Package glossaries Info: Writing glossary file Master.glo on input line 94.
\glo@acronym@file=\write7
\openout7 = `Master.acn'.
-Package glossaries Info: Writing glossary file Master.acn on input line 93.
+Package glossaries Info: Writing glossary file Master.acn on input line 94.
(./Glossary.tex)
(./Master.aux)
\openout1 = `Master.aux'.
-LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 110.
-LaTeX Font Info: ... okay on input line 110.
-LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 110.
-LaTeX Font Info: ... okay on input line 110.
-LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 110.
-LaTeX Font Info: ... okay on input line 110.
-LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 110.
-LaTeX Font Info: ... okay on input line 110.
-LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 110.
-LaTeX Font Info: ... okay on input line 110.
-LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 110.
-LaTeX Font Info: ... okay on input line 110.
-LaTeX Font Info: Try loading font information for T1+ptm on input line 110.
+LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 111.
+LaTeX Font Info: ... okay on input line 111.
+LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 111.
+LaTeX Font Info: ... okay on input line 111.
+LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 111.
+LaTeX Font Info: ... okay on input line 111.
+LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 111.
+LaTeX Font Info: ... okay on input line 111.
+LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 111.
+LaTeX Font Info: ... okay on input line 111.
+LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 111.
+LaTeX Font Info: ... okay on input line 111.
+LaTeX Font Info: Try loading font information for T1+ptm on input line 111.
(/usr/share/texmf-texlive/tex/latex/psnfss/t1ptm.fd
File: t1ptm.fd 2001/06/04 font definitions for T1/ptm.
)
Package scrbase Info: No captions found for `german'
-(scrbase) --> skipped on input line 110.
+(scrbase) --> skipped on input line 111.
Package scrbase Info: No captions found for `ngerman'
-(scrbase) --> skipped on input line 110.
+(scrbase) --> skipped on input line 111.
(/usr/share/texmf-texlive/tex/latex/ucs/ucsencs.def
File: ucsencs.def 2003/11/29 Fixes to fontencodings LGR, T3
@@ -948,7 +952,7 @@ File: ucsencs.def 2003/11/29 Fixes to fontencodings LGR, T3
[Loading MPS to PDF converter (version 2006.09.02).]
\scratchcounter=\count171
\scratchdimen=\dimen221
-\scratchbox=\box50
+\scratchbox=\box51
\nofMPsegments=\count172
\nofMParguments=\count173
\everyMPshowfont=\toks51
@@ -997,17 +1001,17 @@ Non-PDF special ignored!
{/var/lib/texmf/fonts/map/pdftex/updmap/pdftex.map} <../Images/unisiegel.pdf>])
LaTeX Font Info: Font shape `T1/ptm/bx/n' in size <10.95> not available
-(Font) Font shape `T1/ptm/b/n' tried instead on input line 120.
+(Font) Font shape `T1/ptm/b/n' tried instead on input line 121.
(../Content/Abstract.tex) [2]
-LaTeX Font Info: Try loading font information for T1+phv on input line 133.
+LaTeX Font Info: Try loading font information for T1+phv on input line 134.
(/usr/share/texmf-texlive/tex/latex/psnfss/t1phv.fd
File: t1phv.fd 2001/06/04 scalable font definitions for T1/phv.
)
LaTeX Font Info: Font shape `T1/phv/bx/n' in size <10.95> not available
-(Font) Font shape `T1/phv/b/n' tried instead on input line 133.
+(Font) Font shape `T1/phv/b/n' tried instead on input line 134.
LaTeX Font Info: Font shape `T1/ptm/bx/n' in size <20.74> not available
-(Font) Font shape `T1/ptm/b/n' tried instead on input line 133.
+(Font) Font shape `T1/ptm/b/n' tried instead on input line 134.
(./Master.lof)
\tf@lof=\write8
\openout8 = `Master.lof'.
@@ -1038,10 +1042,10 @@ Class scrbook Info: You've told me to use the font selection of the element
(scrbook) on input line 4.
Class scrbook Info: You've told me to use the font selection of the element
(scrbook) `sectioning' that is an alias of element `disposition'
-(scrbook) on input line 36.
+(scrbook) on input line 35.
Class scrbook Info: You've told me to use the font selection of the element
(scrbook) `sectioning' that is an alias of element `disposition'
-(scrbook) on input line 37.
+(scrbook) on input line 36.
)
\tf@toc=\write10
\openout10 = `Master.toc'.
@@ -1081,39 +1085,56 @@ LaTeX Font Info: Try loading font information for T1+pcr on input line 85.
(/usr/share/texmf-texlive/tex/latex/psnfss/t1pcr.fd
File: t1pcr.fd 2001/06/04 font definitions for T1/pcr.
-) [5]
+)
+<../Images/template.png, id=54, 1003.75pt x 53.19875pt>
+File: ../Images/template.png Graphic file (type png)
+
+<use ../Images/template.png>
+Overfull \hbox (13.11272pt too wide) in paragraph at lines 95--96
+ [][]
+ []
+
+[5 <../Images/template.png (PNG copy)>]
LaTeX Font Info: Font shape `T1/ptm/bx/n' in size <12> not available
-(Font) Font shape `T1/ptm/b/n' tried instead on input line 115.
- [6] [7] [8] [9]
-[10] [11] [12]
+(Font) Font shape `T1/ptm/b/n' tried instead on input line 117.
+ [6] [7] [8] [9] [10] [11] [12]
Underfull \vbox (badness 2318) has occurred while \output is active []
[13]
[14] [15] [16] [17] [18] [19] [20] [21]
-LaTeX Warning: Reference `sec:parameters' on page 22 undefined on input line 71
-8.
+LaTeX Warning: Reference `sec:parameters' on page 22 undefined on input line 72
+0.
[22]
-LaTeX Warning: Citation `gsm0502' on page 23 undefined on input line 731.
+LaTeX Warning: Citation `gsm0502' on page 23 undefined on input line 733.
LaTeX Warning: Reference `tab:channel_configurations' on page 23 undefined on i
-nput line 732.
+nput line 734.
[23]
-LaTeX Warning: Citation `3gpp_ts_0405' on page 24 undefined on input line 790.
+LaTeX Warning: Citation `3gpp_ts_0405' on page 24 undefined on input line 792.
+
+LaTeX Warning: Citation `3gpp_ts_0406' on page 24 undefined on input line 792.
-LaTeX Warning: Citation `3gpp_ts_0406' on page 24 undefined on input line 790.
+[24]
-[24]) [25] [26
+LaTeX Warning: Citation `fox' on page 25 undefined on input line 804.
+LaTeX Warning: Citation `fox' on page 25 undefined on input line 813.
-] (./Master.bbl
+
+LaTeX Warning: Citation `dennis' on page 25 undefined on input line 817.
+
+
+LaTeX Warning: Citation `ccc_catcher' on page 25 undefined on input line 817.
+
+[25]) [26] (./Master.bbl
Underfull \hbox (badness 2818) in paragraph at lines 4--8
[]\T1/ptm/m/n/10.95 Radio ac-cess net-work: Ra-dio trans-mis-sion and re-cep-ti
on. GSM 05.05,
@@ -1164,6 +1185,9 @@ Underfull \hbox (badness 3428) in paragraph at lines 50--53
[1
+
+
+
]) (../Content/Appendix.tex) (./Master.acr [2]
Underfull \hbox (badness 2626) in paragraph at lines 24--24
[]|\T1/ptm/m/n/10.95 Conférence Eu-ropéenne des Ad-min-is-tra-tions des
@@ -1185,11 +1209,11 @@ LaTeX Warning: There were undefined references.
)
Here is how much of TeX's memory you used:
- 23135 strings out of 493848
- 439315 string characters out of 1152824
- 656159 words of memory out of 3000000
- 25823 multiletter control sequences out of 15000+50000
- 73378 words of font info for 99 fonts, out of 3000000 for 9000
+ 23212 strings out of 493848
+ 440468 string characters out of 1152824
+ 656533 words of memory out of 3000000
+ 25894 multiletter control sequences out of 15000+50000
+ 73495 words of font info for 100 fonts, out of 3000000 for 9000
714 hyphenation exceptions out of 8191
69i,13n,72p,1076b,1342s stack positions out of 5000i,500n,10000p,200000b,50000s
{/usr/share/texmf-texlive/fonts/enc/dvips/base/8r.enc}</usr/share/texmf-texli
@@ -1199,13 +1223,14 @@ amsfonts/cm/cmmi8.pfb></usr/share/texmf-texlive/fonts/type1/public/amsfonts/cm/
cmr10.pfb></usr/share/texmf-texlive/fonts/type1/public/amsfonts/cm/cmr8.pfb></u
sr/share/texmf-texlive/fonts/type1/public/amsfonts/cm/cmsy10.pfb></usr/share/te
xmf-texlive/fonts/type1/public/amsfonts/cm/cmsy8.pfb></usr/share/texmf-texlive/
-fonts/type1/urw/courier/ucrr8a.pfb></usr/share/texmf-texlive/fonts/type1/urw/ti
-mes/utmb8a.pfb></usr/share/texmf-texlive/fonts/type1/urw/times/utmr8a.pfb></usr
-/share/texmf-texlive/fonts/type1/urw/times/utmr8a.pfb></usr/share/texmf-texlive
-/fonts/type1/urw/times/utmri8a.pfb>
-Output written on Master.pdf (39 pages, 262852 bytes).
+fonts/type1/public/eurosym/feymr10.pfb></usr/share/texmf-texlive/fonts/type1/ur
+w/courier/ucrr8a.pfb></usr/share/texmf-texlive/fonts/type1/urw/times/utmb8a.pfb
+></usr/share/texmf-texlive/fonts/type1/urw/times/utmr8a.pfb></usr/share/texmf-t
+exlive/fonts/type1/urw/times/utmr8a.pfb></usr/share/texmf-texlive/fonts/type1/u
+rw/times/utmri8a.pfb>
+Output written on Master.pdf (39 pages, 275215 bytes).
PDF statistics:
- 184 PDF objects out of 1000 (max. 8388607)
+ 189 PDF objects out of 1000 (max. 8388607)
0 named destinations out of 1000 (max. 500000)
- 18 words of extra memory for PDF output out of 10000 (max. 10000000)
+ 23 words of extra memory for PDF output out of 10000 (max. 10000000)
diff --git a/Tex/Master/Master.pdf b/Tex/Master/Master.pdf
index 30f0bb0..1032fed 100644
--- a/Tex/Master/Master.pdf
+++ b/Tex/Master/Master.pdf
Binary files differ
diff --git a/Tex/Master/Master.synctex.gz b/Tex/Master/Master.synctex.gz
index 45f03b6..c72eb4d 100644
--- a/Tex/Master/Master.synctex.gz
+++ b/Tex/Master/Master.synctex.gz
Binary files differ
diff --git a/Tex/Master/Master.tex b/Tex/Master/Master.tex
index 2fde9fb..78bac2e 100644
--- a/Tex/Master/Master.tex
+++ b/Tex/Master/Master.tex
@@ -15,6 +15,7 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\usepackage{titlepage}
+\usepackage{eurosym}
%\usepackage{a4wide}
%\usepackage{caption}
\usepackage{appendix}
diff --git a/Tex/Master/Master.toc b/Tex/Master/Master.toc
index 529c106..cff2c35 100644
--- a/Tex/Master/Master.toc
+++ b/Tex/Master/Master.toc
@@ -30,8 +30,7 @@
\contentsline {paragraph}{Data Link (Layer 2):}{24}
\contentsline {paragraph}{Network (Layer 3):}{25}
\contentsline {section}{\numberline {2.4}IMSI-Catcher}{25}
-\contentsline {subsection}{\numberline {2.4.1}Mode of Operation}{25}
-\contentsline {subsection}{\numberline {2.4.2}Possible Attacks}{25}
-\contentsline {subsection}{\numberline {2.4.3}Law Situation in Germany}{25}
+\contentsline {subsection}{\numberline {2.4.1}Mode of Operation}{26}
+\contentsline {subsection}{\numberline {2.4.2}Law Situation in Germany}{26}
\contentsline {chapter}{Bibliography}{I}
\contentsline {chapter}{Acronyms}{III}
8' href='#n2078'>2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368
/*****************************************************************************\
**                                                                           **
** Linux Call Router                                                         **
**                                                                           **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg                                              **
**                                                                           **
** Asterisk socket client                                                    **
**                                                                           **
\*****************************************************************************/

/*

Registering to LCR:

To connect, open an LCR socket and send a MESSAGE_HELLO to socket with
the application name. This name is unique an can be used for routing calls.
Now the channel driver is linked to LCR and can receive and make calls.


Call is initiated by LCR:

If a call is received from LCR, a MESSAGE_NEWREF is received first.
A new chan_call instance is created. The call reference (ref) is given by
MESSAGE_NEWREF. The state is CHAN_LCR_STATE_IN_PREPARE.
After receiving MESSAGE_SETUP from LCR, the ast_channel instance is created
using ast_channel_alloc(1).  The setup information is given to asterisk.
The new Asterisk instance pointer (ast) is stored to chan_call structure.
The state changes to CHAN_LCR_STATE_IN_SETUP.


Call is initiated by Asterisk:

If a call is requested from Asterisk, a new chan_call instance is created.
The new Asterisk instance pointer (ast) is stored to chan_call structure.
The current call ref is set to 0, the state is CHAN_LCR_STATE_OUT_PREPARE.
If the call is received (lcr_call) A MESSASGE_NEWREF is sent to LCR requesting
a new call reference (ref).
Further dialing information is queued.
After the new callref is received by special MESSAGE_NEWREF reply, new ref
is stored in the chan_call structure. 
The setup information is sent to LCR using MESSAGE_SETUP.
The state changes to CHAN_LCR_STATE_OUT_SETUP.


Call is in process:

During call process, messages are received and sent.
The state changes accordingly.
Any message is allowed to be sent to LCR at any time except MESSAGE_RELEASE.
If a MESSAGE_OVERLAP is received, further dialing is required.
Queued dialing information, if any, is sent to LCR using MESSAGE_DIALING.
In this case, the state changes to CHAN_LCR_STATE_OUT_DIALING.


Call is released by LCR:

A MESSAGE_RELEASE is received with the call reference (ref) to be released.
The current ref is set to 0, to indicate released reference.
The state changes to CHAN_LCR_STATE_RELEASE.
ast_queue_hangup() is called, if asterisk instance (ast) exists, if not,
the chan_call instance is destroyed.
After lcr_hangup() is called-back by Asterisk, the chan_call instance
is destroyed, because the current ref is set to 0 and the state equals
CHAN_LCR_STATE_RELEASE.
If the ref is 0 and the state is not CHAN_LCR_STATE_RELEASE, see the proceedure
"Call is released by Asterisk".


Call is released by Asterisk:

lcr_hangup() is called-back by Asterisk. If the call reference (ref) is set,
a MESSAGE_RELEASE is sent to LCR and the chan_call instance is destroyed.
If the ref is 0 and the state is not CHAN_LCR_STATE_RELEASE, the new state is
set to CHAN_LCR_STATE_RELEASE.
Later, if the MESSAGE_NEWREF reply is received, a MESSAGE_RELEASE is sent to
LCR and the chan_call instance is destroyed.
If the ref is 0 and the state is CHAN_LCR_STATE_RELEASE, see the proceedure
"Call is released by LCR".

*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <errno.h>
#include <sys/types.h>
#include <time.h>
//#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/un.h>

#include <semaphore.h>

#include <asterisk/module.h>
#include <asterisk/channel.h>
#include <asterisk/config.h>
#include <asterisk/logger.h>
#include <asterisk/pbx.h>
#include <asterisk/options.h>
#include <asterisk/io.h>
#include <asterisk/frame.h>
#include <asterisk/translate.h>
#include <asterisk/cli.h>
#include <asterisk/musiconhold.h>
#include <asterisk/dsp.h>
#include <asterisk/translate.h>
#include <asterisk/file.h>
#include <asterisk/callerid.h>
#include <asterisk/indications.h>
#include <asterisk/app.h>
#include <asterisk/features.h>
#include <asterisk/sched.h>

#include "extension.h"
#include "message.h"
#include "callerid.h"
#include "lcrsocket.h"
#include "cause.h"
#include "bchannel.h"
#include "options.h"
#include "chan_lcr.h"

CHAN_LCR_STATE // state description structure
MESSAGES // message text

unsigned char flip_bits[256];

int lcr_debug=1;
int mISDN_created=1;

char lcr_type[]="lcr";

pthread_t chan_tid;
ast_mutex_t chan_lock; /* global lock */
ast_mutex_t log_lock; /* logging log */
int quit;

int glob_channel = 0;

int lcr_sock = -1;

struct admin_list {
	struct admin_list *next;
	struct admin_message msg;
} *admin_first = NULL;

static struct ast_channel_tech lcr_tech;

/*
 * logging
 */
void chan_lcr_log(int type, const char *file, int line, const char *function, struct chan_call *call, struct ast_channel *ast, const char *fmt, ...)
{
	char buffer[1024];
	char call_text[128] = "NULL";
	char ast_text[128] = "NULL";
	va_list args;

	ast_mutex_lock(&log_lock);

	va_start(args,fmt);
	vsnprintf(buffer,sizeof(buffer)-1,fmt,args);
	buffer[sizeof(buffer)-1]=0;
	va_end(args);

	if (call)
		sprintf(call_text, "%ld", call->ref);
	if (ast)
		strncpy(ast_text, ast->name, sizeof(ast_text)-1);
	ast_text[sizeof(ast_text)-1] = '\0';
	
	ast_log(type, file, line, function, "[call=%s ast=%s] %s", call_text, ast_text, buffer);

	ast_mutex_unlock(&log_lock);
}

/*
 * channel and call instances
 */
struct chan_call *call_first;

struct chan_call *find_call_ref(unsigned long ref)
{
	struct chan_call *call = call_first;

	while(call)
	{
		if (call->ref == ref)
			break;
		call = call->next;
	}
	return(call);
}

#if 0
struct chan_call *find_call_ast(struct ast_channel *ast)
{
	struct chan_call *call = call_first;

	while(call)
	{
		if (call->ast == ast)
			break;
		call = call->next;
	}
	return(call);
}

struct chan_call *find_call_handle(unsigned long handle)
{
	struct chan_call *call = call_first;

	while(call)
	{
		if (call->bchannel_handle == handle)
			break;
		call = call->next;
	}
	return(call);
}
#endif

void free_call(struct chan_call *call)
{
	struct chan_call **temp = &call_first;

	while(*temp)
	{
		if (*temp == call)
		{
			*temp = (*temp)->next;
			if (call->pipe[0] > -1)
				close(call->pipe[0]);
			if (call->pipe[1] > -1)
				close(call->pipe[1]);
			if (call->bchannel)
			{
				if (call->bchannel->call != call)
					CERROR(call, NULL, "Linked bchannel structure has no link to us.\n");
				call->bchannel->call = NULL;
			}
			if (call->bridge_call)
			{
				if (call->bridge_call->bridge_call != call)
					CERROR(call, NULL, "Linked call structure has no link to us.\n");
				call->bridge_call->bridge_call = NULL;
			}
			CDEBUG(call, NULL, "Call instance freed.\n");
			free(call);
			return;
		}
		temp = &((*temp)->next);
	}
	CERROR(call, NULL, "Call instance not found in list.\n");
}

struct chan_call *alloc_call(void)
{
	struct chan_call **callp = &call_first;

	while(*callp)
		callp = &((*callp)->next);

	*callp = (struct chan_call *)calloc(1, sizeof(struct chan_call));
	if (*callp)
		memset(*callp, 0, sizeof(struct chan_call));
	if (pipe((*callp)->pipe) < 0) {
		CERROR(*callp, NULL, "Failed to create pipe.\n");
		free_call(*callp);
		return(NULL);
	}
	CDEBUG(*callp, NULL, "Call instance allocated.\n");
	return(*callp);
}


unsigned short new_bridge_id(void)
{
	struct chan_call *call;
	unsigned short id = 1;

	/* search for lowest bridge id that is not in use and not 0 */
	while(id)
	{
		call = call_first;
		while(call)
		{
			if (call->bridge_id == id)
				break;
			call = call->next;
		}
		if (!call)
			break;
		id++;
	}
	CDEBUG(NULL, NULL, "New bridge ID %d.\n", id);
	return(id);
}

/*
 * enque message to LCR
 */
int send_message(int message_type, unsigned long ref, union parameter *param)
{
	struct admin_list *admin, **adminp;

	if (lcr_sock < 0) {
		CDEBUG(NULL, NULL, "Ignoring message %d, because socket is closed.\n", message_type);
		return -1;
	}
	CDEBUG(NULL, NULL, "Sending %s to socket.\n", messages_txt[message_type]);

	adminp = &admin_first;
	while(*adminp)
		adminp = &((*adminp)->next);
	admin = (struct admin_list *)calloc(1, sizeof(struct admin_list));
	if (!admin) {
		CERROR(NULL, NULL, "No memory for message to LCR.\n");
		return -1;
	}
	*adminp = admin;

	admin->msg.message = ADMIN_MESSAGE;
	admin->msg.u.msg.type = message_type;
	admin->msg.u.msg.ref = ref;
	memcpy(&admin->msg.u.msg.param, param, sizeof(union parameter));

	return(0);
}

/*
 * apply options (in locked state)
 */
void apply_opt(struct chan_call *call, char *data)
{
	union parameter newparam;
	char string[1024], *p = string, *opt, *key;
	int gain, i, newmode = 0;

	strncpy(string, data, sizeof(string)-1);
	string[sizeof(string)-1] = '\0';

	/* parse options */
	while((opt = strsep(&p, ":")))
	{
		switch(opt[0]) {
		case 'd':
			if (opt[1] == '\0') {
				CERROR(call, call->ast, "Option 'd' (display) expects parameter.\n", opt);
				break;
			}
			CDEBUG(call, call->ast, "Option 'd' (display) with text '%s'.\n", opt+1);
			if (call->state == CHAN_LCR_STATE_OUT_PREPARE)
				strncpy(call->display, opt+1, sizeof(call->display)-1);
			else {
				memset(&newparam, 0, sizeof(union parameter));
				strncpy(newparam.notifyinfo.display, opt+1, sizeof(newparam.notifyinfo.display)-1);
				send_message(MESSAGE_NOTIFY, call->ref, &newparam);
			}
			break;
		case 'n':
			if (opt[1] != '\0') {
				CERROR(call, call->ast, "Option 'n' (no DTMF) expects no parameter.\n", opt);
				break;
			}
			CDEBUG(call, call->ast, "Option 'n' (no DTMF).\n");
			call->no_dtmf = 1;
			break;
		case 'c':
			if (opt[1] == '\0') {
				CERROR(call, call->ast, "Option 'c' (encrypt) expects key parameter.\n", opt);
				break;
			}
			key = opt+1;
			/* check for 0xXXXX... type of key */
			if (!!strncmp((char *)key, "0x", 2)) {
				CERROR(call, call->ast, "Option 'c' (encrypt) expects key parameter starting with '0x'.\n", opt);
				break;
			}
			key+=2;
			if (strlen(key) > 56*2 || (strlen(key) % 1)) {
				CERROR(call, call->ast, "Option 'c' (encrypt) expects key parameter with max 56 bytes ('0x' + 112 characters)\n", opt);
				break;
			}
			i = 0;
			while(*key)
			{
				if (*key>='0' && *key<='9')
					call->bf_key[i] = (*key-'0') << 8;
				else if (*key>='a' && *key<='f')
					call->bf_key[i] = (*key-'a'+10) << 8;
				else if (*key>='A' && *key<='F')
					call->bf_key[i] = (*key-'A'+10) << 8;
				else
					break;
				key++;
				if (*key>='0' && *key<='9')
					call->bf_key[i] += (*key - '0');
				else if (*key>='a' && *key<='f')
					call->bf_key[i] += (*key - 'a' + 10);
				else if (*key>='A' && *key<='F')
					call->bf_key[i] += (*key - 'A' + 10);
				else
					break;
				key++;
				i++;
			}
			if (*key) {
				CERROR(call, call->ast, "Option 'c' (encrypt) expects key parameter with hex values 0-9,a-f.\n");
				break;
			}
			call->bf_len = i;
			CDEBUG(call, call->ast, "Option 'c' (encrypt) blowfish key '%s' (len=%d).\n", opt+1, i);
			if (call->bchannel)
				bchannel_blowfish(call->bchannel, call->bf_key, call->bf_len);
			break;
		case 'h':
			if (opt[1] != '\0') {
				CERROR(call, call->ast, "Option 'h' (HDLC) expects no parameter.\n", opt);
				break;
			}
			CDEBUG(call, call->ast, "Option 'h' (HDLC).\n");
			if (!call->hdlc) {
				call->hdlc = 1;
				newmode = 1;
			}
			break;
		case 't':
			if (opt[1] != '\0') {
				CERROR(call, call->ast, "Option 't' (transparent) expects no parameter.\n", opt);
				break;
			}
			CDEBUG(call, call->ast, "Option 't' (transparent).\n");
			if (!call->transparent) {
				call->transparent = 1;
				newmode = 1;
			}
			break;
		case 'e':
			if (opt[1] == '\0') {
				CERROR(call, call->ast, "Option 'e' (echo cancel) expects parameter.\n", opt);
				break;
			}
			CDEBUG(call, call->ast, "Option 'e' (echo cancel) with config '%s'.\n", opt+1);
			strncpy(call->pipeline, opt+1, sizeof(call->pipeline)-1);
			if (call->bchannel)
				bchannel_pipeline(call->bchannel, call->pipeline);
			break;
#if 0
		case 's':
			if (opt[1] != '\0') {
				CERROR(call, call->ast, "Option 's' (inband DTMF) expects no parameter.\n", opt);
				break;
			}
			CDEBUG(call, call->ast, "Option 's' (inband DTMF).\n");
			call->inband_dtmf = 1;
todo
			break;
#endif
		case 'v':
			if (opt[1] != 'r' && opt[1] != 't') {
				CERROR(call, call->ast, "Option 'v' (volume) expects parameter.\n", opt);
				break;
			}
			gain = atoi(opt+2);
			if (gain < -8 || gain >8) {
				CERROR(call, call->ast, "Option 'v' (volume) expects parameter in range of -8 through 8.\n");
				break;
			}
			CDEBUG(call, call->ast, "Option 'v' (volume) with gain 2^%d.\n", gain);
			if (opt[1] == 'r') {
				call->rx_gain = gain;
				if (call->bchannel)
					bchannel_gain(call->bchannel, call->rx_gain, 0);
			} else {
				call->tx_gain = gain;
				if (call->bchannel)
					bchannel_gain(call->bchannel, call->tx_gain, 1);
			}
			break;
		default:
			CERROR(call, call->ast, "Option '%s' unknown.\n", opt);
		}
	}		
	
	/* re-open, if bchannel is created */
	if (call->bchannel && call->bchannel->b_sock > -1) {
		bchannel_destroy(call->bchannel);
		if (bchannel_create(call->bchannel, ((call->transparent)?1:0) + ((call->hdlc)?2:0)))
			bchannel_activate(call->bchannel, 1);
	}
}

/*
 * send setup info to LCR
 * this function is called, when asterisk call is received and ref is received
 */
static void send_setup_to_lcr(struct chan_call *call)
{
	union parameter newparam;
	struct ast_channel *ast = call->ast;

	if (!call->ast || !call->ref)
		return;

	CDEBUG(call, call->ast, "Sending setup to LCR. (interface=%s dialstring=%s)\n", call->interface, call->dialstring);

	/* send setup message to LCR */
	memset(&newparam, 0, sizeof(union parameter));
       	newparam.setup.dialinginfo.itype = INFO_ITYPE_ISDN;	
       	newparam.setup.dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
	strncpy(newparam.setup.dialinginfo.id, call->dialstring, sizeof(newparam.setup.dialinginfo.id)-1);
	strncpy(newparam.setup.dialinginfo.interfaces, call->interface, sizeof(newparam.setup.dialinginfo.interfaces)-1);
       	newparam.setup.callerinfo.itype = INFO_ITYPE_CHAN;	
       	newparam.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN;
	strncpy(newparam.setup.callerinfo.display, call->display, sizeof(newparam.setup.callerinfo.display)-1);
	call->display[0] = '\0';
	if (ast->cid.cid_num) if (ast->cid.cid_num[0])
		strncpy(newparam.setup.callerinfo.id, ast->cid.cid_num, sizeof(newparam.setup.callerinfo.id)-1);
	if (ast->cid.cid_name) if (ast->cid.cid_name[0])
		strncpy(newparam.setup.callerinfo.name, ast->cid.cid_name, sizeof(newparam.setup.callerinfo.name)-1);
	if (ast->cid.cid_rdnis) if (ast->cid.cid_rdnis[0])
	{
		strncpy(newparam.setup.redirinfo.id, ast->cid.cid_rdnis, sizeof(newparam.setup.redirinfo.id)-1);
       		newparam.setup.redirinfo.itype = INFO_ITYPE_CHAN;	
 	      	newparam.setup.redirinfo.ntype = INFO_NTYPE_UNKNOWN;	
	}
	switch(ast->cid.cid_pres & AST_PRES_RESTRICTION)
	{
		case AST_PRES_ALLOWED:
		newparam.setup.callerinfo.present = INFO_PRESENT_ALLOWED;
		break;
		case AST_PRES_RESTRICTED:
		newparam.setup.callerinfo.present = INFO_PRESENT_RESTRICTED;
		break;
		case AST_PRES_UNAVAILABLE:
		newparam.setup.callerinfo.present = INFO_PRESENT_NOTAVAIL;
		break;
		default:
		newparam.setup.callerinfo.present = INFO_PRESENT_NULL;
	}
	switch(ast->cid.cid_ton)
	{
		case 4:
		newparam.setup.callerinfo.ntype = INFO_NTYPE_SUBSCRIBER;
		break;
		case 2:
		newparam.setup.callerinfo.ntype = INFO_NTYPE_NATIONAL;
		break;
		case 1:
		newparam.setup.callerinfo.ntype = INFO_NTYPE_INTERNATIONAL;
		break;
		default:
		newparam.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN;
	}
	newparam.setup.capainfo.bearer_capa = ast->transfercapability;
	newparam.setup.capainfo.bearer_info1 = (options.law=='a')?3:2;
	newparam.setup.capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
	newparam.setup.capainfo.hlc = INFO_HLC_NONE;
	newparam.setup.capainfo.exthlc = INFO_HLC_NONE;
	send_message(MESSAGE_SETUP, call->ref, &newparam);

	/* change to outgoing setup state */
	call->state = CHAN_LCR_STATE_OUT_SETUP;
}

/*
 * send dialing info to LCR
 * this function is called, when setup acknowledge is received and dialing
 * info is available.
 */
static void send_dialque_to_lcr(struct chan_call *call)
{
	union parameter newparam;

	if (!call->ast || !call->ref || !call->dialque[0])
		return;
	
	CDEBUG(call, call->ast, "Sending dial queue to LCR. (dialing=%s)\n", call->dialque);

	/* send setup message to LCR */
	memset(&newparam, 0, sizeof(union parameter));
	strncpy(newparam.information.id, call->dialque, sizeof(newparam.information.id)-1);
	call->dialque[0] = '\0';
	send_message(MESSAGE_INFORMATION, call->ref, &newparam);
}

/*
 * in case of a bridge, the unsupported message can be forwarded directly
 * to the remote call.
 */
static void bridge_message_if_bridged(struct chan_call *call, int message_type, union parameter *param)
{
	/* check bridge */
	if (!call) return;
	if (!call->bridge_call) return;
	CDEBUG(call, NULL, "Sending message due briding.\n");
	send_message(message_type, call->bridge_call->ref, param);
}

/*
 * send release message to LCR and import bchannel if exported
 */
static void send_release_and_import(struct chan_call *call, int cause, int location)
{
	union parameter newparam;

	/* importing channel */
	if (call->bchannel) {
		memset(&newparam, 0, sizeof(union parameter));
		newparam.bchannel.type = BCHANNEL_RELEASE;
		newparam.bchannel.handle = call->bchannel->handle;
		send_message(MESSAGE_BCHANNEL, call->ref, &newparam);
	}
	/* sending release */
	memset(&newparam, 0, sizeof(union parameter));
	newparam.disconnectinfo.cause = cause;
	newparam.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
	send_message(MESSAGE_RELEASE, call->ref, &newparam);
}

/*
 * check if extension matches and start asterisk
 * if it can match, proceed
 * if not, release
 */
static void lcr_start_pbx(struct chan_call *call, struct ast_channel *ast, int complete)
{
	int cause, ret;
	union parameter newparam;

	CDEBUG(call, ast, "Try to start pbx. (exten=%s context=%s complete=%s)\n", ast->exten, ast->context, complete?"yes":"no");
	
	if (complete)
	{
		/* if not match */
		if (!ast_canmatch_extension(ast, ast->context, ast->exten, 1, call->oad))
		{
			CDEBUG(call, ast, "Got 'sending complete', but extension '%s' will not match at context '%s' - releasing.\n", ast->exten, ast->context);
			cause = 1;
			goto release;
		}
		if (!ast_exists_extension(ast, ast->context, ast->exten, 1, call->oad))
		{
			CDEBUG(call, ast, "Got 'sending complete', but extension '%s' would match at context '%s', if more digits would be dialed - releasing.\n", ast->exten, ast->context);
			cause = 28;
			goto release;
		}
		CDEBUG(call, ast, "Got 'sending complete', extensions matches.\n");
		/* send setup acknowledge to lcr */
		memset(&newparam, 0, sizeof(union parameter));
		send_message(MESSAGE_PROCEEDING, call->ref, &newparam);

		/* change state */
		call->state = CHAN_LCR_STATE_IN_PROCEEDING;

		goto start;
	}

	if (ast_canmatch_extension(ast, ast->context, ast->exten, 1, call->oad))
	{
		/* send setup acknowledge to lcr */
		if (call->state != CHAN_LCR_STATE_IN_DIALING) {
			memset(&newparam, 0, sizeof(union parameter));
			send_message(MESSAGE_OVERLAP, call->ref, &newparam);
		}

		/* change state */
		call->state = CHAN_LCR_STATE_IN_DIALING;

		/* if match, start pbx */
		if (ast_exists_extension(ast, ast->context, ast->exten, 1, call->oad)) {
			CDEBUG(call, ast, "Extensions matches.\n");
			goto start;
		}

		/* if can match */
		CDEBUG(call, ast, "Extensions may match, if more digits are dialed.\n");
		return;
	}

	/* if not match */
	cause = 1;
	release:
	/* release lcr */
	CDEBUG(call, ast, "Releasing due to extension missmatch.\n");
	send_release_and_import(call, cause, LOCATION_PRIVATE_LOCAL);
	call->ref = 0;
	/* release asterisk */
	ast->hangupcause = call->cause;
	/* change to release state */
	call->state = CHAN_LCR_STATE_RELEASE;
	ast_hangup(ast); // call will be destroyed here
	return;
	
	start:
	/* send setup to asterisk */
	CDEBUG(call, ast, "Starting call to Asterisk due to matching extension.\n");
	ret = ast_pbx_start(ast);
	if (ret < 0)
	{
		cause = (ret==-2)?34:27;
		goto release;
	}
	call->pbx_started = 1;
	return;
}

/*
 * incoming setup from LCR
 */
static void lcr_in_setup(struct chan_call *call, int message_type, union parameter *param)
{
	struct ast_channel *ast;

	CDEBUG(call, NULL, "Incomming setup from LCR. (callerid %s, dialing %s)\n", param->setup.callerinfo.id, param->setup.dialinginfo.id);

	/* create asterisk channel instrance */
	ast = ast_channel_alloc(1, AST_STATE_RESERVED, NULL, NULL, "", NULL, "", 0, "%s/%d", lcr_type, ++glob_channel);
	if (!ast)
	{
		/* release */
		CERROR(call, NULL, "Failed to create Asterisk channel - releasing.\n");
		send_release_and_import(call, CAUSE_RESSOURCEUNAVAIL, LOCATION_PRIVATE_LOCAL);
		/* remove call */
		free_call(call);
		return;
	}
	/* link together */
	call->ast = ast;
	ast->tech_pvt = call;
	ast->tech = &lcr_tech;
	ast->fds[0] = call->pipe[0];
	
	/* fill setup information */
	if (param->setup.dialinginfo.id)
		strncpy(ast->exten, param->setup.dialinginfo.id, AST_MAX_EXTENSION-1);
	if (param->setup.context[0])
		strncpy(ast->context, param->setup.context, AST_MAX_CONTEXT-1);
	else
		strncpy(ast->context, param->setup.callerinfo.interface, AST_MAX_CONTEXT-1);
	if (param->setup.callerinfo.id[0])
		ast->cid.cid_num = strdup(param->setup.callerinfo.id);
	if (param->setup.callerinfo.name[0])
		ast->cid.cid_name = strdup(param->setup.callerinfo.name);
	if (param->setup.redirinfo.id[0])
		ast->cid.cid_name = strdup(numberrize_callerinfo(param->setup.callerinfo.id, param->setup.callerinfo.ntype, options.national, options.international));
	switch (param->setup.callerinfo.present)
	{
		case INFO_PRESENT_ALLOWED:
			ast->cid.cid_pres = AST_PRES_ALLOWED;
		break;
		case INFO_PRESENT_RESTRICTED:
			ast->cid.cid_pres = AST_PRES_RESTRICTED;
		break;
		default:
			ast->cid.cid_pres = AST_PRES_UNAVAILABLE;
	}
	switch (param->setup.callerinfo.ntype)
	{
		case INFO_NTYPE_SUBSCRIBER:
			ast->cid.cid_ton = 4;
		break;
		case INFO_NTYPE_NATIONAL:
			ast->cid.cid_ton = 2;
		break;
		case INFO_NTYPE_INTERNATIONAL:
			ast->cid.cid_ton = 1;
		break;
		default:
			ast->cid.cid_ton = 0;
	}
	ast->transfercapability = param->setup.capainfo.bearer_capa;
	/* enable hdlc if transcap is data */
	if (ast->transfercapability == INFO_BC_DATAUNRESTRICTED
	 || ast->transfercapability == INFO_BC_DATARESTRICTED
	 || ast->transfercapability == INFO_BC_VIDEO)
		call->hdlc = 1;
	strncpy(call->oad, numberrize_callerinfo(param->setup.callerinfo.id, param->setup.callerinfo.ntype, options.national, options.international), sizeof(call->oad)-1);

	/* configure channel */
	ast->nativeformats = (options.law=='a')?AST_FORMAT_ALAW:AST_FORMAT_ULAW;
	ast->readformat = ast->rawreadformat = ast->nativeformats;
	ast->writeformat = ast->rawwriteformat =  ast->nativeformats;
	ast->priority = 1;
	ast->hangupcause = 0;

	/* change state */
	call->state = CHAN_LCR_STATE_IN_SETUP;

	lcr_start_pbx(call, ast, param->setup.dialinginfo.sending_complete);
}

/*
 * incoming setup acknowledge from LCR
 */
static void lcr_in_overlap(struct chan_call *call, int message_type, union parameter *param)
{
	if (!call->ast) return;

	CDEBUG(call, call->ast, "Incomming setup acknowledge from LCR.\n");

	/* send pending digits in dialque */
	if (call->dialque[0])
		send_dialque_to_lcr(call);
	/* change to overlap state */
	call->state = CHAN_LCR_STATE_OUT_DIALING;
}

/*
 * incoming proceeding from LCR
 */
static void lcr_in_proceeding(struct chan_call *call, int message_type, union parameter *param)
{
	CDEBUG(call, call->ast, "Incomming proceeding from LCR.\n");

	/* change state */
	call->state = CHAN_LCR_STATE_OUT_PROCEEDING;
	/* send event to asterisk */
	if (call->ast && call->pbx_started)
		ast_queue_control(call->ast, AST_CONTROL_PROCEEDING);
}

/*
 * incoming alerting from LCR
 */
static void lcr_in_alerting(struct chan_call *call, int message_type, union parameter *param)
{
	CDEBUG(call, call->ast, "Incomming alerting from LCR.\n");

	/* change state */
	call->state = CHAN_LCR_STATE_OUT_ALERTING;
	/* send event to asterisk */
	if (call->ast && call->pbx_started)
		ast_queue_control(call->ast, AST_CONTROL_RINGING);
}

/*
 * incoming connect from LCR
 */
static void lcr_in_connect(struct chan_call *call, int message_type, union parameter *param)
{
	union parameter newparam;

	CDEBUG(call, call->ast, "Incomming connect (answer) from LCR.\n");

	/* change state */
	call->state = CHAN_LCR_STATE_CONNECT;
	/* request bchannel */
	if (!call->bchannel) {
		CDEBUG(call, call->ast, "Requesting B-channel.\n");
		memset(&newparam, 0, sizeof(union parameter));
		newparam.bchannel.type = BCHANNEL_REQUEST;
		send_message(MESSAGE_BCHANNEL, call->ref, &newparam);
	}
	/* copy connectinfo */
	memcpy(&call->connectinfo, &param->connectinfo, sizeof(struct connect_info));
	/* send event to asterisk */
	if (call->ast && call->pbx_started)
		ast_queue_control(call->ast, AST_CONTROL_ANSWER);
}

/*
 * incoming disconnect from LCR
 */
static void lcr_in_disconnect(struct chan_call *call, int message_type, union parameter *param)
{
	struct ast_channel *ast = call->ast;

	CDEBUG(call, call->ast, "Incomming disconnect from LCR. (cause=%d)\n", param->disconnectinfo.cause);

	/* change state */
	call->state = CHAN_LCR_STATE_IN_DISCONNECT;
	/* save cause */
	call->cause = param->disconnectinfo.cause;
	call->location = param->disconnectinfo.location;
	/* if bridge, forward disconnect and return */
#ifdef TODO
	feature flag
	if (call->bridge_call)
	{
		CDEBUG(call, call->ast, "Only signal disconnect via bridge.\n");
		bridge_message_if_bridged(call, message_type, param);
		return;
	}
#endif
	/* release lcr with same cause */
	send_release_and_import(call, call->cause, call->location);
	call->ref = 0;
	/* change to release state */
	call->state = CHAN_LCR_STATE_RELEASE;
	/* release asterisk */
	if (ast)
	{
		ast->hangupcause = call->cause;
		if (call->pbx_started)
			ast_queue_hangup(ast);
		else {
			ast_hangup(ast); // call will be destroyed here
		}
	}
}

/*
 * incoming setup acknowledge from LCR
 */
static void lcr_in_release(struct chan_call *call, int message_type, union parameter *param)
{
	struct ast_channel *ast = call->ast;

	CDEBUG(call, call->ast, "Incomming release from LCR, releasing ref. (cause=%d)\n", param->disconnectinfo.cause);

	/* release ref */
	call->ref = 0;
	/* change to release state */
	call->state = CHAN_LCR_STATE_RELEASE;
	/* copy release info */
	if (!call->cause)
	{
	       call->cause = param->disconnectinfo.cause;
	       call->location = param->disconnectinfo.location;
	}
	/* if we have an asterisk instance, send hangup, else we are done */
	if (ast)
	{
		ast->hangupcause = call->cause;
		if (call->pbx_started)
			ast_queue_hangup(ast);
		else {
			ast_hangup(ast); // call will be destroyed here
		}
	} else
	{
		free_call(call);
	}
	
}

/*
 * incoming information from LCR
 */
static void lcr_in_information(struct chan_call *call, int message_type, union parameter *param)
{
	struct ast_channel *ast = call->ast;
	struct ast_frame fr;
	char *p;

	CDEBUG(call, call->ast, "Incoming information from LCR. (dialing=%s)\n", param->information.id);
	
	if (!ast) return;

	/* pbx not started */
	if (!call->pbx_started)
	{
		CDEBUG(call, call->ast, "Asterisk not started, adding digits to number.\n");
		strncat(ast->exten, param->information.id, AST_MAX_EXTENSION-1);
		lcr_start_pbx(call, ast, param->information.sending_complete);
		return;
	}
	
	/* copy digits */
	p = param->information.id;
	if (call->state == CHAN_LCR_STATE_IN_DIALING && *p)
	{
		CDEBUG(call, call->ast, "Asterisk is started, sending DTMF frame.\n");
		while (*p)
		{
			/* send digit to asterisk */
			memset(&fr, 0, sizeof(fr));
			fr.frametype = AST_FRAME_DTMF;
			fr.subclass = *p;
			fr.delivery = ast_tv(0, 0);
			ast_queue_frame(call->ast, &fr);
			p++;
		}
	}
	/* use bridge to forware message not supported by asterisk */
	if (call->state == CHAN_LCR_STATE_CONNECT) {
		CDEBUG(call, call->ast, "Call is connected, briding.\n");
		bridge_message_if_bridged(call, message_type, param);
	}
}

/*
 * incoming information from LCR
 */
static void lcr_in_notify(struct chan_call *call, int message_type, union parameter *param)
{
	union parameter newparam;

	CDEBUG(call, call->ast, "Incomming notify from LCR. (notify=%d)\n", param->notifyinfo.notify);

	/* request bchannel, if call is resumed and we don't have it */
	if (param->notifyinfo.notify == INFO_NOTIFY_USER_RESUMED && !call->bchannel && call->ref) {
		CDEBUG(call, call->ast, "Reqesting bchannel at resume.\n");
		memset(&newparam, 0, sizeof(union parameter));
		newparam.bchannel.type = BCHANNEL_REQUEST;
		send_message(MESSAGE_BCHANNEL, call->ref, &newparam);
	}

	if (!call->ast) return;

	/* use bridge to forware message not supported by asterisk */
	bridge_message_if_bridged(call, message_type, param);
}

/*
 * incoming information from LCR
 */
static void lcr_in_facility(struct chan_call *call, int message_type, union parameter *param)
{
	CDEBUG(call, call->ast, "Incomming facility from LCR.\n");

	if (!call->ast) return;

	/* use bridge to forware message not supported by asterisk */
	bridge_message_if_bridged(call, message_type, param);
}

/*
 * got dtmf from bchannel
 */
void lcr_in_dtmf(struct chan_call *call, int val)
{
	struct ast_channel *ast = call->ast;
	struct ast_frame fr;

	if (!ast)
		return;
	if (!call->pbx_started)
		return;

	CDEBUG(call, call->ast, "Frowarding DTMF digit '%c' to Asterisk.\n", val);

	/* send digit to asterisk */
	memset(&fr, 0, sizeof(fr));
	fr.frametype = AST_FRAME_DTMF;
	fr.subclass = val;
	fr.delivery = ast_tv(0, 0);
	ast_queue_frame(call->ast, &fr);
}

/*
 * message received from LCR
 */
int receive_message(int message_type, unsigned long ref, union parameter *param)
{
	struct bchannel *bchannel;
	struct chan_call *call;
	union parameter newparam;

	memset(&newparam, 0, sizeof(union parameter));

	/* handle bchannel message*/
	if (message_type == MESSAGE_BCHANNEL)
	{
		switch(param->bchannel.type)
		{
			case BCHANNEL_ASSIGN:
			CDEBUG(NULL, NULL, "Received BCHANNEL_ASSIGN message. (handle=%08lx)\n", param->bchannel.handle);
			if ((bchannel = find_bchannel_handle(param->bchannel.handle)))
			{
				CERROR(NULL, NULL, "bchannel handle %x already assigned.\n", (int)param->bchannel.handle);
				return(-1);
			}
			/* create bchannel */
			bchannel = alloc_bchannel(param->bchannel.handle);
			if (!bchannel)
			{
				CERROR(NULL, NULL, "alloc bchannel handle %x failed.\n", (int)param->bchannel.handle);
				return(-1);
			}

			/* configure channel */
			bchannel->b_tx_gain = param->bchannel.tx_gain;
			bchannel->b_rx_gain = param->bchannel.rx_gain;
			strncpy(bchannel->b_pipeline, param->bchannel.pipeline, sizeof(bchannel->b_pipeline)-1);
			if (param->bchannel.crypt_len && param->bchannel.crypt_len <= sizeof(bchannel->b_bf_key))
			{
				bchannel->b_bf_len = param->bchannel.crypt_len;
				memcpy(bchannel->b_bf_key, param->bchannel.crypt, param->bchannel.crypt_len);
			}
			bchannel->b_txdata = 0;
			bchannel->b_dtmf = 1;
			bchannel->b_tx_dejitter = 1;

			/* in case, ref is not set, this bchannel instance must
			 * be created until it is removed again by LCR */
			/* link to call */
			call = find_call_ref(ref);
			if (call)
			{
				bchannel->call = call;
				call->bchannel = bchannel;
				if (call->dtmf)
					bchannel_dtmf(bchannel, 1);
				if (call->bf_len)
					bchannel_blowfish(bchannel, call->bf_key, call->bf_len);
				if (call->pipeline[0])
					bchannel_pipeline(bchannel, call->pipeline);
				if (call->rx_gain)
					bchannel_gain(bchannel, call->rx_gain, 0);
				if (call->tx_gain)
					bchannel_gain(bchannel, call->tx_gain, 1);
				if (call->bridge_id) {
					CDEBUG(call, call->ast, "Join bchannel, because call is already bridged.\n");
					bchannel_join(bchannel, call->bridge_id);
				}
			}
			if (bchannel_create(bchannel, ((call->transparent)?1:0) + ((call->hdlc)?2:0)))
				bchannel_activate(bchannel, 1);
			/* acknowledge */
			newparam.bchannel.type = BCHANNEL_ASSIGN_ACK;
			newparam.bchannel.handle = param->bchannel.handle;
			send_message(MESSAGE_BCHANNEL, 0, &newparam);
			/* if call has released before bchannel is assigned */
			if (!call) {
				newparam.bchannel.type = BCHANNEL_RELEASE;
				newparam.bchannel.handle = param->bchannel.handle;
				send_message(MESSAGE_BCHANNEL, 0, &newparam);
			}

			break;

			case BCHANNEL_REMOVE:
			CDEBUG(NULL, NULL, "Received BCHANNEL_REMOVE message. (handle=%08lx)\n", param->bchannel.handle);
			if (!(bchannel = find_bchannel_handle(param->bchannel.handle)))
			{
				CERROR(NULL, NULL, "Bchannel handle %x not assigned.\n", (int)param->bchannel.handle);
				return(-1);
			}
			/* unklink from call and destroy bchannel */
			free_bchannel(bchannel);

			/* acknowledge */
			newparam.bchannel.type = BCHANNEL_REMOVE_ACK;
			newparam.bchannel.handle = param->bchannel.handle;
			send_message(MESSAGE_BCHANNEL, 0, &newparam);
			
			break;

			default:
			CDEBUG(NULL, NULL, "Received unknown bchannel message %d.\n", param->bchannel.type);
		}
		return(0);
	}

	/* handle new ref */
	if (message_type == MESSAGE_NEWREF)
	{
		if (param->direction)
		{
			/* new ref from lcr */
			CDEBUG(NULL, NULL, "Received new ref by LCR, due to incomming call. (ref=%ld)\n", ref);
			if (!ref || find_call_ref(ref))
			{
				CERROR(NULL, NULL, "Illegal new ref %ld received.\n", ref);
				return(-1);
			}
			/* allocate new call instance */
			call = alloc_call();
			/* new state */
			call->state = CHAN_LCR_STATE_IN_PREPARE;
			/* set ref */
			call->ref = ref;
			/* wait for setup (or release from asterisk) */
		} else
		{
			/* new ref, as requested from this remote application */
			CDEBUG(NULL, NULL, "Received new ref by LCR, as requested from chan_lcr. (ref=%ld)\n", ref);
			call = find_call_ref(0);
			if (!call)
			{
				/* send release, if ref does not exist */
				CDEBUG(NULL, NULL, "No call found, that requests a ref.\n");
				send_release_and_import(call, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL);
				return(0);
			}
			/* store new ref */
			call->ref = ref;
			/* send pending setup info */
			if (call->state == CHAN_LCR_STATE_OUT_PREPARE)
				send_setup_to_lcr(call);
			/* release if asterisk has signed off */
			else if (call->state == CHAN_LCR_STATE_RELEASE)
			{
				/* send release */
				if (call->cause)
					send_release_and_import(call, call->cause, call->location);
				else
					send_release_and_import(call, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL);
				/* free call */
				free_call(call);
				return(0);
			}
		}
		return(0);
	}

	/* check ref */
	if (!ref)
	{
		CERROR(NULL, NULL, "Received message %d without ref.\n", message_type);
		return(-1);
	}
	call = find_call_ref(ref);
	if (!call)
	{
		/* ignore ref that is not used (anymore) */
		CDEBUG(NULL, NULL, "Message %d from LCR ignored, because no call instance found.\n", message_type);
		return(0);
	}

	/* handle messages */
	switch(message_type)
	{
		case MESSAGE_SETUP:
		lcr_in_setup(call, message_type, param);
		break;

		case MESSAGE_OVERLAP:
		lcr_in_overlap(call, message_type, param);
		break;

		case MESSAGE_PROCEEDING:
		lcr_in_proceeding(call, message_type, param);
		break;

		case MESSAGE_ALERTING:
		lcr_in_alerting(call, message_type, param);
		break;

		case MESSAGE_CONNECT:
		lcr_in_connect(call, message_type, param);
		break;

		case MESSAGE_DISCONNECT:
		lcr_in_disconnect(call, message_type, param);
		break;

		case MESSAGE_RELEASE:
		lcr_in_release(call, message_type, param);
		break;

		case MESSAGE_INFORMATION:
		lcr_in_information(call, message_type, param);
		break;

		case MESSAGE_NOTIFY:
		lcr_in_notify(call, message_type, param);
		break;

		case MESSAGE_FACILITY:
		lcr_in_facility(call, message_type, param);
		break;

		case MESSAGE_PATTERN: // audio available from LCR
		break;

		case MESSAGE_NOPATTERN: // audio not available from LCR
		break;

		case MESSAGE_AUDIOPATH: // if remote audio connected or hold
		call->audiopath = param->audiopath;
		break;

		default:
		CDEBUG(call, call->ast, "Message %d from LCR unhandled.\n", message_type);
		break;
	}
	return(0);
}

/*
 * release all calls (due to broken socket)
 */
static void release_all_calls(void)
{
	struct chan_call *call;

again:
	call = call_first;
	while(call) {
		/* no ast, so we may directly free call */
		if (!call->ast) {
			CDEBUG(call, NULL, "Freeing call, because no Asterisk channel is linked.\n");
			free_call(call);
			goto again;
		}
		/* already in release process */
		if (call->state == CHAN_LCR_STATE_RELEASE) {
			call = call->next;
			continue;
		}
		/* release or queue release */
		call->ref = 0;
		call->state = CHAN_LCR_STATE_RELEASE;
		if (!call->pbx_started) {
			CDEBUG(call, call->ast, "Releasing call, because no Asterisk channel is not started.\n");
			ast_hangup(call->ast); // call will be destroyed here
			goto again;
		}
		CDEBUG(call, call->ast, "Queue call release, because Asterisk channel is running.\n");
		ast_queue_hangup(call->ast);
		call = call->next;
	}

	/* release all bchannels */
	while(bchannel_first)
		free_bchannel(bchannel_first);
}


/* asterisk handler
 * warning! not thread safe
 * returns -1 for socket error, 0 for no work, 1 for work
 */
int handle_socket(void)
{
	int work = 0;
	int len;
	struct admin_list *admin;
	struct admin_message msg;

	/* read from socket */
	len = read(lcr_sock, &msg, sizeof(msg));
	if (len == 0)
	{
		CERROR(NULL, NULL, "Socket closed.\n");
		return(-1); // socket closed
	}
	if (len > 0)
	{
		if (len != sizeof(msg))
		{
			CERROR(NULL, NULL, "Socket short read. (len %d)\n", len);
			return(-1); // socket error
		}
		if (msg.message != ADMIN_MESSAGE)
		{
			CERROR(NULL, NULL, "Socket received illegal message %d.\n", msg.message);
			return(-1);
		}
		receive_message(msg.u.msg.type, msg.u.msg.ref, &msg.u.msg.param);
		work = 1;
	} else
	{
		if (errno != EWOULDBLOCK)
		{
			CERROR(NULL, NULL, "Socket failed (errno %d).\n", errno);
			return(-1);
		}
	}

	/* write to socket */
	if (!admin_first)
		return(work);
	admin = admin_first;
	len = write(lcr_sock, &admin->msg, sizeof(msg));
	if (len == 0)
	{
		CERROR(NULL, NULL, "Socket closed.\n");
		return(-1); // socket closed
	}
	if (len > 0)
	{
		if (len != sizeof(msg))
		{
			CERROR(NULL, NULL, "Socket short write. (len %d)\n", len);
			return(-1); // socket error
		}
		/* free head */
		admin_first = admin->next;
		free(admin);

		work = 1;
	} else
	{
		if (errno != EWOULDBLOCK)
		{
			CERROR(NULL, NULL, "Socket failed (errno %d).\n", errno);
			return(-1);
		}
	}

	return(work);
}

/*
 * open and close socket and thread
 */
int open_socket(void)
{
	int ret;
	char *socket_name = SOCKET_NAME;
	int conn;
	struct sockaddr_un sock_address;
	unsigned long on = 1;
	union parameter param;

	/* open socket */
	if ((lcr_sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
	{
		CERROR(NULL, NULL, "Failed to create socket.\n");
		return(lcr_sock);
	}

	/* set socket address and name */
	memset(&sock_address, 0, sizeof(sock_address));
	sock_address.sun_family = PF_UNIX;
	strcpy(sock_address.sun_path, socket_name);

	/* connect socket */
	if ((conn = connect(lcr_sock, (struct sockaddr *)&sock_address, SUN_LEN(&sock_address))) < 0)
	{
		close(lcr_sock);
		lcr_sock = -1;
		CDEBUG(NULL, NULL, "Failed to connect to socket '%s'. Is LCR running?\n", sock_address.sun_path);
		return(conn);
	}

	/* set non-blocking io */
	if ((ret = ioctl(lcr_sock, FIONBIO, (unsigned char *)(&on))) < 0)
	{
		close(lcr_sock);
		lcr_sock = -1;
		CERROR(NULL, NULL, "Failed to set socket into non-blocking IO.\n");
		return(ret);
	}

	/* enque hello message */
	memset(&param, 0, sizeof(param));
	strcpy(param.hello.application, "asterisk");
	send_message(MESSAGE_HELLO, 0, &param);

	return(lcr_sock);
}

void close_socket(void)
{
	struct admin_list *admin, *temp;
	
	/* flush pending messages */
	admin = admin_first;
	while(admin) {
		temp = admin;
		admin = admin->next;
		free(temp);
	}
	admin_first = NULL;

	/* close socket */
	if (lcr_sock >= 0)	
		close(lcr_sock);
	lcr_sock = -1;
}

void sighandler(int sigset)
{
}

static void *chan_thread(void *arg)
{
	int work;
	int ret;
	union parameter param;
	time_t retry = 0, now;

	bchannel_pid = getpid();

//	signal(SIGPIPE, sighandler);
	
	memset(&param, 0, sizeof(union parameter));
	if (lcr_sock < 0)
		time(&retry);

	ast_mutex_lock(&chan_lock);

	while(!quit) {
		work = 0;

		if (lcr_sock > 0) {
			/* handle socket */
			ret = handle_socket();
			if (ret < 0) {
				CERROR(NULL, NULL, "Handling of socket failed - closing for some seconds.\n");
				close_socket();
				release_all_calls();
				time(&retry);
			}
			if (ret)
				work = 1;
		} else {
			time(&now);
			if (retry && now-retry > 5) {
				CDEBUG(NULL, NULL, "Retry to open socket.\n");
				retry = 0;
				if (open_socket() < 0) {
					time(&retry);
				}
				work = 1;
			}
					
		}

		/* handle mISDN */
		ret = bchannel_handle();
		if (ret)
			work = 1;
		
		if (!work) {
			ast_mutex_unlock(&chan_lock);
			usleep(30000);
			ast_mutex_lock(&chan_lock);
		}
	}

	close_socket();

	CERROR(NULL, NULL, "Thread exit.\n");
	
	ast_mutex_unlock(&chan_lock);

//	signal(SIGPIPE, SIG_DFL);

	return NULL;
}

/*
 * new asterisk instance
 */
static
struct ast_channel *lcr_request(const char *type, int format, void *data, int *cause)
{
	char exten[256], *dial, *interface, *opt;
	struct ast_channel *ast;
        struct chan_call *call;

	ast_mutex_lock(&chan_lock);
	CDEBUG(NULL, NULL, "Received request from Asterisk. (data=%s)\n", (char *)data);

	/* if socket is closed */
	if (lcr_sock < 0)
	{
		CERROR(NULL, NULL, "Rejecting call from Asterisk, because LCR not running.\n");
		return NULL;
	}

	/* create call instance */
	call = alloc_call();
	if (!call)
	{
		/* failed to create instance */
		return NULL;
	}

	/* create asterisk channel instrance */
	ast = ast_channel_alloc(1, AST_STATE_RESERVED, NULL, NULL, "", NULL, "", 0, "%s/%d", lcr_type, ++glob_channel);
	if (!ast)
	{
		CERROR(NULL, NULL, "Failed to create Asterisk channel.\n");
		free_call(call);
		/* failed to create instance */
		return NULL;
	}
	ast->tech = &lcr_tech;
	ast->tech_pvt = (void *)1L; // set pointer or asterisk will not call
	/* configure channel */
	ast->nativeformats = (options.law=='a')?AST_FORMAT_ALAW:AST_FORMAT_ULAW;
	ast->readformat = ast->rawreadformat = ast->nativeformats;
	ast->writeformat = ast->rawwriteformat =  ast->nativeformats;
	ast->priority = 1;
	ast->hangupcause = 0;

	/* link together */
	call->ast = ast;
	ast->tech_pvt = call;
	ast->fds[0] = call->pipe[0];
	call->pbx_started = 0;
	/* set state */
	call->state = CHAN_LCR_STATE_OUT_PREPARE;

	/*
	 * Extract interface, dialstring, options from data.
	 * Formats can be:
	 * 	<dialstring>
	 * 	<interface>/<dialstring>
	 * 	<interface>/<dialstring>/options
	 */
	strncpy(exten, (char *)data, sizeof(exten)-1);
	exten[sizeof(exten)-1] = '\0';
	if ((dial = strchr(exten, '/'))) {
		*dial++ = '\0';
		interface = exten;
		if ((opt = strchr(dial, '/')))
			*opt++ = '\0';
		else
			opt = "";
	} else {
		dial = exten;
		interface = "";
		opt = "";
	}
	strncpy(call->interface, interface, sizeof(call->interface)-1);
	strncpy(call->dialstring, dial, sizeof(call->dialstring)-1);
	apply_opt(call, (char *)opt);

	/* if hdlc is forced by option, we change transcap to data */
	if (call->hdlc
	 && ast->transfercapability != INFO_BC_DATAUNRESTRICTED
	 && ast->transfercapability != INFO_BC_DATARESTRICTED
	 && ast->transfercapability != INFO_BC_VIDEO)
		ast->transfercapability = INFO_BC_DATAUNRESTRICTED;

	ast_mutex_unlock(&chan_lock);
	return ast;
}

/*
 * call from asterisk
 */
static int lcr_call(struct ast_channel *ast, char *dest, int timeout)
{
	union parameter newparam;
        struct chan_call *call;

	ast_mutex_lock(&chan_lock);
        call = ast->tech_pvt;
	if (!call) {
		CERROR(NULL, ast, "Received call from Asterisk, but call instance does not exist.\n");
		ast_mutex_unlock(&chan_lock);
		return -1;
	}

	CDEBUG(NULL, ast, "Received call from Asterisk.\n");

	/* pbx process is started */
	call->pbx_started = 1;
	/* send MESSAGE_NEWREF */
	memset(&newparam, 0, sizeof(union parameter));
	newparam.direction = 0; /* request from app */
	send_message(MESSAGE_NEWREF, 0, &newparam);

	/* set hdlc if capability requires hdlc */
	if (ast->transfercapability == INFO_BC_DATAUNRESTRICTED
	 || ast->transfercapability == INFO_BC_DATARESTRICTED
	 || ast->transfercapability == INFO_BC_VIDEO)
		call->hdlc = 1;
		
	ast_mutex_unlock(&chan_lock);
	return 0; 
}

static int lcr_digit(struct ast_channel *ast, char digit)
{
        struct chan_call *call;
	union parameter newparam;
	char buf[]="x";

	/* only pass IA5 number space */
	if (digit > 126 || digit < 32)
		return 0;

	ast_mutex_lock(&chan_lock);
        call = ast->tech_pvt;
	if (!call) {
		CERROR(NULL, ast, "Received digit from Asterisk, but no call instance exists.\n");
		ast_mutex_unlock(&chan_lock);
		return -1;
	}

	CDEBUG(call, ast, "Received digit '%c' from Asterisk.\n", digit);

	/* send information or queue them */
	if (call->ref && call->state == CHAN_LCR_STATE_OUT_DIALING)
	{
		CDEBUG(call, ast, "Sending digit to LCR, because we are in dialing state.\n");
		memset(&newparam, 0, sizeof(union parameter));
		newparam.information.id[0] = digit;
		newparam.information.id[1] = '\0';
		send_message(MESSAGE_INFORMATION, call->ref, &newparam);
	} else
	if (!call->ref
	 && (call->state == CHAN_LCR_STATE_OUT_PREPARE || call->state == CHAN_LCR_STATE_OUT_SETUP))
	{
		CDEBUG(call, ast, "Queue digits, because we are in setup/dialing state and have no ref yet.\n");
		*buf = digit;
		strncat(call->dialque, buf, strlen(call->dialque)-1);
	}

	ast_mutex_unlock(&chan_lock);
	return(0);
}

static int lcr_answer(struct ast_channel *ast)
{
	union parameter newparam;
        struct chan_call *call;

	ast_mutex_lock(&chan_lock);
        call = ast->tech_pvt;
	if (!call) {
		CERROR(NULL, ast, "Received answer from Asterisk, but no call instance exists.\n");
		ast_mutex_unlock(&chan_lock);
		return -1;
	}
	
	CDEBUG(call, ast, "Received answer from Asterisk.\n");
		
	/* copy connectinfo, if bridged */
	if (call->bridge_call)
		memcpy(&call->connectinfo, &call->bridge_call->connectinfo, sizeof(struct connect_info));
	/* send connect message to lcr */
	memset(&newparam, 0, sizeof(union parameter));
	memcpy(&newparam.connectinfo, &call->connectinfo, sizeof(struct connect_info));
	send_message(MESSAGE_CONNECT, call->ref, &newparam);
	/* change state */
	call->state = CHAN_LCR_STATE_CONNECT;
	/* request bchannel */
	if (!call->bchannel) {
		CDEBUG(call, ast, "Requesting B-channel.\n");
		memset(&newparam, 0, sizeof(union parameter));
		newparam.bchannel.type = BCHANNEL_REQUEST;
		send_message(MESSAGE_BCHANNEL, call->ref, &newparam);
	}
	/* enable keypad */
//	memset(&newparam, 0, sizeof(union parameter));
//	send_message(MESSAGE_ENABLEKEYPAD, call->ref, &newparam);
	/* enable dtmf */
	if (call->no_dtmf)
		CDEBUG(call, ast, "DTMF is disabled by option.\n");
	else
		call->dtmf = 1;
	
   	ast_mutex_unlock(&chan_lock);
        return 0;
}

static int lcr_hangup(struct ast_channel *ast)
{
        struct chan_call *call;
	pthread_t tid = pthread_self();

	if (!pthread_equal(tid, chan_tid))
		ast_mutex_lock(&chan_lock);
        call = ast->tech_pvt;
	if (!call) {
		CERROR(NULL, ast, "Received hangup from Asterisk, but no call instance exists.\n");
		if (!pthread_equal(tid, chan_tid))
			ast_mutex_unlock(&chan_lock);
		return -1;
	}

	if (!pthread_equal(tid, chan_tid))
		CDEBUG(call, ast, "Received hangup from Asterisk thread.\n");
	else
		CDEBUG(call, ast, "Received hangup from LCR thread.\n");

	/* disconnect asterisk, maybe not required */
	ast->tech_pvt = NULL;
	ast->fds[0] = -1;
	if (call->ref)
	{
		/* release */
		CDEBUG(call, ast, "Releasing ref and freeing call instance.\n");
		if (ast->hangupcause > 0)
			send_release_and_import(call, ast->hangupcause, LOCATION_PRIVATE_LOCAL);
		else
			send_release_and_import(call, CAUSE_RESSOURCEUNAVAIL, LOCATION_PRIVATE_LOCAL);
		/* remove call */
		free_call(call);
		if (!pthread_equal(tid, chan_tid))
			ast_mutex_unlock(&chan_lock);
		return 0;
	} else
	{
		/* ref is not set, due to prepare setup or release */
		if (call->state == CHAN_LCR_STATE_RELEASE)
		{
			/* we get the response to our release */
			CDEBUG(call, ast, "Freeing call instance, because we have no ref AND we are requesting no ref.\n");
			free_call(call);
		} else
		{
			/* during prepare, we change to release state */
			CDEBUG(call, ast, "We must wait until we received our ref, until we can free call instance.\n");
			call->state = CHAN_LCR_STATE_RELEASE;
		}
	} 
	if (!pthread_equal(tid, chan_tid))
		ast_mutex_unlock(&chan_lock);
	return 0;
}

static int lcr_write(struct ast_channel *ast, struct ast_frame *f)
{
        struct chan_call *call;

	if (!f->subclass)
		CDEBUG(NULL, ast, "No subclass\n");
	if (!(f->subclass & ast->nativeformats))
		CDEBUG(NULL, ast, "Unexpected format.\n");
	
	ast_mutex_lock(&chan_lock);
        call = ast->tech_pvt;
	if (!call) {
		ast_mutex_unlock(&chan_lock);
		return -1;
	}
	if (call->bchannel && f->samples)
		bchannel_transmit(call->bchannel, f->data, f->samples);
	ast_mutex_unlock(&chan_lock);
	return 0;
}


static struct ast_frame *lcr_read(struct ast_channel *ast)
{
        struct chan_call *call;
	int i, len;
	unsigned char *p;

	ast_mutex_lock(&chan_lock);
        call = ast->tech_pvt;
	if (!call) {
		ast_mutex_unlock(&chan_lock);
		return NULL;
	}
	if (call->pipe[0] > -1) {
		len = read(call->pipe[0], call->read_buff, sizeof(call->read_buff));
		if (len <= 0) {
			close(call->pipe[0]);
			call->pipe[0] = -1;
			return NULL;
		}
	}

	p = call->read_buff;
	for (i = 0; i < len; i++) {
		*p = flip_bits[*p];
		p++;
	}

	call->read_fr.frametype = AST_FRAME_VOICE;
	call->read_fr.subclass = ast->nativeformats;
	call->read_fr.datalen = len;
	call->read_fr.samples = len;
	call->read_fr.delivery = ast_tv(0,0);
	call->read_fr.data = call->read_buff;
	ast_mutex_unlock(&chan_lock);

	return &call->read_fr;
}

static int lcr_indicate(struct ast_channel *ast, int cond, const void *data, size_t datalen)
{
	union parameter newparam;
        int res = 0;
        struct chan_call *call;

	ast_mutex_lock(&chan_lock);
        call = ast->tech_pvt;
	if (!call) {
		CERROR(NULL, ast, "Received indicate from Asterisk, but no call instance exists.\n");
		ast_mutex_unlock(&chan_lock);
		return -1;
	}

        switch (cond) {
                case AST_CONTROL_BUSY:
			CDEBUG(call, ast, "Received indicate AST_CONTROL_BUSY from Asterisk.\n");
			ast_setstate(ast, AST_STATE_BUSY);
			if (call->state != CHAN_LCR_STATE_OUT_DISCONNECT) {
				/* send message to lcr */
				memset(&newparam, 0, sizeof(union parameter));
				newparam.disconnectinfo.cause = 17;
				newparam.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
				send_message(MESSAGE_DISCONNECT, call->ref, &newparam);
				/* change state */
				call->state = CHAN_LCR_STATE_OUT_DISCONNECT;
			}
			break;
                case AST_CONTROL_CONGESTION:
			CDEBUG(call, ast, "Received indicate AST_CONTROL_CONGESTION from Asterisk. (cause %d)\n", ast->hangupcause);
			if (call->state != CHAN_LCR_STATE_OUT_DISCONNECT) {
				/* send message to lcr */
				memset(&newparam, 0, sizeof(union parameter));
				newparam.disconnectinfo.cause = ast->hangupcause;
				newparam.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
				send_message(MESSAGE_DISCONNECT, call->ref, &newparam);
				/* change state */
				call->state = CHAN_LCR_STATE_OUT_DISCONNECT;
			}
			break;
                case AST_CONTROL_PROCEEDING:
			CDEBUG(call, ast, "Received indicate AST_CONTROL_PROCEEDING from Asterisk.\n");
			if (call->state == CHAN_LCR_STATE_IN_SETUP
			 || call->state == CHAN_LCR_STATE_IN_DIALING) {
				/* send message to lcr */
				memset(&newparam, 0, sizeof(union parameter));
				send_message(MESSAGE_PROCEEDING, call->ref, &newparam);
				/* change state */
				call->state = CHAN_LCR_STATE_IN_PROCEEDING;
			}
			break;
                case AST_CONTROL_RINGING:
			CDEBUG(call, ast, "Received indicate AST_CONTROL_RINGING from Asterisk.\n");
			ast_setstate(ast, AST_STATE_RINGING);
			if (call->state == CHAN_LCR_STATE_IN_SETUP
			 || call->state == CHAN_LCR_STATE_IN_DIALING
			 || call->state == CHAN_LCR_STATE_IN_PROCEEDING) {
				/* send message to lcr */
				memset(&newparam, 0, sizeof(union parameter));
				send_message(MESSAGE_ALERTING, call->ref, &newparam);
				/* change state */
				call->state = CHAN_LCR_STATE_IN_ALERTING;
			}
			break;
                case -1:
			CDEBUG(call, ast, "Received indicate -1.\n");
                        res = -1;
			break;

                case AST_CONTROL_VIDUPDATE:
			CDEBUG(call, ast, "Received indicate AST_CONTROL_VIDUPDATE.\n");
                        res = -1;
                        break;
                case AST_CONTROL_HOLD:
			CDEBUG(call, ast, "Received indicate AST_CONTROL_HOLD from Asterisk.\n");
			/* send message to lcr */
			memset(&newparam, 0, sizeof(union parameter));
			newparam.notifyinfo.notify = INFO_NOTIFY_REMOTE_HOLD;
			send_message(MESSAGE_NOTIFY, call->ref, &newparam);
			
			/*start music onhold*/
			ast_moh_start(ast,data,ast->musicclass);
                        break;
                case AST_CONTROL_UNHOLD:
			CDEBUG(call, ast, "Received indicate AST_CONTROL_UNHOLD from Asterisk.\n");
			/* send message to lcr */
			memset(&newparam, 0, sizeof(union parameter));
			newparam.notifyinfo.notify = INFO_NOTIFY_REMOTE_RETRIEVAL;
			send_message(MESSAGE_NOTIFY, call->ref, &newparam);

			/*stop moh*/
                	ast_moh_stop(ast);
		        break;

                default:
			CERROR(call, ast, "Received indicate from Asterisk with unknown condition %d.\n", cond);
                        res = -1;
			break;
        }

	/* return */
	ast_mutex_unlock(&chan_lock);
        return res;
}

/*
 * fixup asterisk
 */
static int lcr_fixup(struct ast_channel *oldast, struct ast_channel *newast)
{
        struct chan_call *call;

	ast_mutex_lock(&chan_lock);
	call = oldast->tech_pvt;
	if (!call) {
		CERROR(NULL, oldast, "Received fixup from Asterisk, but no call instance exists.\n");
		ast_mutex_unlock(&chan_lock);
		return -1;
	}

	CDEBUG(call, oldast, "Received fixup from Asterisk.\n");
	call->ast = newast;
	ast_mutex_lock(&chan_lock);
	return 0;
}

/*
 * send_text asterisk
 */
static int lcr_send_text(struct ast_channel *ast, const char *text)
{
        struct chan_call *call;
	union parameter newparam;

	ast_mutex_lock(&chan_lock);
	call = ast->tech_pvt;
	if (!call) {
		CERROR(NULL, ast, "Received send_text from Asterisk, but no call instance exists.\n");
		ast_mutex_unlock(&chan_lock);
		return -1;
	}

	CDEBUG(call, ast, "Received send_text from Asterisk. (text=%s)\n", text);
	memset(&newparam, 0, sizeof(union parameter));
	strncpy(newparam.notifyinfo.display, text, sizeof(newparam.notifyinfo.display)-1);
	send_message(MESSAGE_NOTIFY, call->ref, &newparam);
	ast_mutex_lock(&chan_lock);
	return 0;
}

/*
 * bridge process
 */
enum ast_bridge_result lcr_bridge(struct ast_channel *ast1,
				  struct ast_channel *ast2, int flags,
				  struct ast_frame **fo,
				  struct ast_channel **rc, int timeoutms)

{
	struct chan_call	*call1, *call2;
	struct ast_channel	*carr[2], *who;
	int			to;
	struct ast_frame	*f;
	int			bridge_id;

	CDEBUG(NULL, NULL, "Received briding request from Asterisk.\n");

	carr[0] = ast1;
	carr[1] = ast2;
	
	/* join via dsp (if the channels are currently open) */
	ast_mutex_lock(&chan_lock);
	bridge_id = new_bridge_id();
	call1 = ast1->tech_pvt;
	call2 = ast2->tech_pvt;
	if (call1 && call2)
	{
		call1->bridge_id = bridge_id;
		if (call1->bchannel)
			bchannel_join(call1->bchannel, bridge_id);
		call1->bridge_call = call2;
	}
	if (call2)
	{
		call2->bridge_id = bridge_id;
		if (call2->bchannel)
			bchannel_join(call2->bchannel, bridge_id);
		call2->bridge_call = call1;
	}
	ast_mutex_unlock(&chan_lock);
	
	while(1) {
		to = -1;
		who = ast_waitfor_n(carr, 2, &to);

		if (!who) {
			CDEBUG(NULL, NULL, "Empty read on bridge, breaking out.\n");
			break;
		}
		f = ast_read(who);
    
		if (!f || f->frametype == AST_FRAME_CONTROL) {
			if (!f)
				CDEBUG(NULL, NULL, "Got hangup.\n");
			else
				CDEBUG(NULL, NULL, "Got CONTROL.\n");
			/* got hangup .. */
			*fo=f;
			*rc=who;
			break;
		}
		
		if ( f->frametype == AST_FRAME_DTMF ) {
			CDEBUG(NULL, NULL, "Got DTMF.\n");
			*fo=f;
			*rc=who;
			break;
		}
	

		if (who == ast1) {
			ast_write(ast2,f);
		}
		else {
			ast_write(ast1,f);
		}
    
	}
	
	CDEBUG(NULL, NULL, "Releasing bride.\n");

	/* split channels */
	ast_mutex_lock(&chan_lock);
	call1 = ast1->tech_pvt;
	call2 = ast2->tech_pvt;
	if (call1)
	{
		call1->bridge_id = 0;
		if (call1->bchannel)
			bchannel_join(call1->bchannel, 0);
		if (call1->bridge_call)
			call1->bridge_call->bridge_call = NULL;
		call1->bridge_call = NULL;
	}
	if (call2)
	{
		call2->bridge_id = 0;
		if (call2->bchannel)
			bchannel_join(call2->bchannel, 0);
		if (call2->bridge_call)
			call2->bridge_call->bridge_call = NULL;
		call2->bridge_call = NULL;
	}

	ast_mutex_unlock(&chan_lock);
	return AST_BRIDGE_COMPLETE;
}
static struct ast_channel_tech lcr_tech = {
	.type="LCR",
	.description="Channel driver for connecting to Linux-Call-Router",
	.requester=lcr_request,
	.send_digit_begin=lcr_digit,
	.call=lcr_call,
	.bridge=lcr_bridge, 
	.hangup=lcr_hangup,
	.answer=lcr_answer,
	.read=lcr_read,
	.write=lcr_write,
	.indicate=lcr_indicate,
	.fixup=lcr_fixup,
	.send_text=lcr_send_text,
	.properties=0
};


/*
 * cli
 */
#if 0
static int lcr_show_lcr (int fd, int argc, char *argv[])
{
	return 0;
}

static int lcr_show_calls (int fd, int argc, char *argv[])
{
	return 0;
}

static int lcr_reload_routing (int fd, int argc, char *argv[])
{
	return 0;
}

static int lcr_reload_interfaces (int fd, int argc, char *argv[])
{
	return 0;
}

static int lcr_port_block (int fd, int argc, char *argv[])
{
	return 0;
}

static int lcr_port_unblock (int fd, int argc, char *argv[])
{
	return 0;
}

static int lcr_port_unload (int fd, int argc, char *argv[])
{
	return 0;
}

static struct ast_cli_entry cli_show_lcr =
{ {"lcr", "show", "lcr", NULL},
 lcr_show_lcr,
 "Shows current states of LCR core",
 "Usage: lcr show lcr\n",
};

static struct ast_cli_entry cli_show_calls =
{ {"lcr", "show", "calls", NULL},
 lcr_show_calls,
 "Shows current calls made by LCR and Asterisk",
 "Usage: lcr show calls\n",
};

static struct ast_cli_entry cli_reload_routing =
{ {"lcr", "reload", "routing", NULL},
 lcr_reload_routing,
 "Reloads routing conf of LCR, current uncomplete calls will be disconnected",
 "Usage: lcr reload routing\n",
};

static struct ast_cli_entry cli_reload_interfaces =
{ {"lcr", "reload", "interfaces", NULL},
 lcr_reload_interfaces,
 "Reloads interfaces conf of LCR",
 "Usage: lcr reload interfaces\n",
};

static struct ast_cli_entry cli_port_block =
{ {"lcr", "port", "block", NULL},
 lcr_port_block,
 "Blocks LCR port for further calls",
 "Usage: lcr port block \"<port>\"\n",
};

static struct ast_cli_entry cli_port_unblock =
{ {"lcr", "port", "unblock", NULL},
 lcr_port_unblock,
 "Unblocks or loads LCR port, port is opened my mISDN",
 "Usage: lcr port unblock \"<port>\"\n",
};

static struct ast_cli_entry cli_port_unload =
{ {"lcr", "port", "unload", NULL},
 lcr_port_unload,
 "Unloads LCR port, port is closes by mISDN",
 "Usage: lcr port unload \"<port>\"\n",
};
#endif



static int lcr_config_exec(struct ast_channel *ast, void *data)
{
	struct chan_call *call;

	ast_mutex_lock(&chan_lock);
	CDEBUG(NULL, ast, "Received lcr_config (data=%s)\n", (char *)data);
	/* find channel */
	call = call_first;
	while(call) {
		if (call->ast == ast)
			break;
		call = call->next;
	}
	if (call)
		apply_opt(call, (char *)data);
	else
		CERROR(NULL, ast, "lcr_config app not called by chan_lcr channel.\n");

	ast_mutex_unlock(&chan_lock);
	return 0;
}

/*
 * module loading and destruction
 */
int load_module(void)
{
	u_short i;

	for (i = 0; i < 256; i++) {
		flip_bits[i] = (i>>7) | ((i>>5)&2) | ((i>>3)&4) | ((i>>1)&8)
			     | (i<<7) | ((i&2)<<5) | ((i&4)<<3) | ((i&8)<<1);
	}

	if (read_options() == 0) {
		CERROR(NULL, NULL, "%s", options_error);
		return AST_MODULE_LOAD_DECLINE;
	}

	ast_mutex_init(&chan_lock);
	ast_mutex_init(&log_lock);

	if (open_socket() < 0) {
		/* continue with closed socket */
	}

	if (bchannel_initialize()) {
		CERROR(NULL, NULL, "Unable to open mISDN device\n");
		close_socket();
		return AST_MODULE_LOAD_DECLINE;
	}
	mISDN_created = 1;

	lcr_tech.capabilities = (options.law=='a')?AST_FORMAT_ALAW:AST_FORMAT_ULAW;
	if (ast_channel_register(&lcr_tech)) {
		CERROR(NULL, NULL, "Unable to register channel class\n");
		bchannel_deinitialize();
		close_socket();
		return AST_MODULE_LOAD_DECLINE;
	}

	ast_register_application("lcr_config", lcr_config_exec, "lcr_config",
				 "lcr_config(<opt><optarg>:<opt>:...)\n"
				 "Sets LCR opts. and optargs\n"
				 "\n"
				 "The available options are:\n"
				 "    d - Send display text on called phone, text is the optarg.\n"
				 "    n - Don't detect dtmf tones on called channel.\n"
				 "    h - Force data call (HDLC).\n" 
				 "    t - Disable all audio features (required for fax application).\n"
				 "    c - Make crypted outgoing call, optarg is keyindex.\n"
				 "    e - Perform echo cancelation on this channel.\n"
				 "        Takes mISDN pipeline option as optarg.\n"
//				 "    s - Send Non Inband DTMF as inband.\n"
				 "   vr - rxgain control\n"
				 "   vt - txgain control\n"
				 "        Volume changes at factor 2 ^ optarg.\n"
		);

 
#if 0	
	ast_cli_register(&cli_show_lcr);
	ast_cli_register(&cli_show_calls);
	ast_cli_register(&cli_reload_routing);
	ast_cli_register(&cli_reload_interfaces);
	ast_cli_register(&cli_port_block);
	ast_cli_register(&cli_port_unblock);
	ast_cli_register(&cli_port_unload);
#endif

	quit = 0;	
	if ((pthread_create(&chan_tid, NULL, chan_thread, NULL)<0))
	{
		/* failed to create thread */
		bchannel_deinitialize();
		close_socket();
		ast_channel_unregister(&lcr_tech);
		return AST_MODULE_LOAD_DECLINE;
	}
	return 0;
}

int unload_module(void)
{
	/* First, take us out of the channel loop */
	CDEBUG(NULL, NULL, "-- Unregistering mISDN Channel Driver --\n");

	quit = 1;
	pthread_join(chan_tid, NULL);	
	
	ast_channel_unregister(&lcr_tech);

        ast_unregister_application("lcr_config");


	if (mISDN_created) {
		bchannel_deinitialize();
		mISDN_created = 0;
	}

	if (lcr_sock >= 0) {
		close(lcr_sock);
		lcr_sock = -1;
	}

	return 0;
}

int reload_module(void)
{
//	reload_config();
	return 0;
}


#define AST_MODULE "chan_lcr"

AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Channel driver for Linux-Call-Router Support (ISDN BRI/PRI)",
		.load = load_module,
		.unload = unload_module,
		.reload = reload_module,
	       );