comparison mncc/intswitch.c @ 2:053f04687106

mncc: initial import from old ThemWi
author Mychaela Falconia <falcon@freecalypso.org>
date Sat, 08 Jun 2024 23:12:12 +0000
parents
children
comparison
equal deleted inserted replaced
1:b161dbfffdaa 2:053f04687106
1 /*
2 * In this module we implement internally switched calls,
3 * going from one GSM subscriber to another.
4 */
5
6 #include <sys/types.h>
7 #include <sys/socket.h>
8 #include <stdio.h>
9 #include <stdint.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <strings.h>
13 #include <syslog.h>
14 #include "../include/mncc.h"
15 #include "../include/gsm48_const.h"
16 #include "struct.h"
17 #include "gsm_call.h"
18
19 extern char *mncc_msg_name();
20
21 void
22 internal_switch_mo_setup(call, msg)
23 struct gsm_call *call;
24 struct gsm_mncc *msg;
25 {
26 struct gsm_call *mt;
27 struct gsm_mncc callproc;
28
29 if (!(msg->fields & MNCC_F_BEARER_CAP)) {
30 syslog(LOG_ERR, "rejecting intsw call 0x%x: no bearer cap",
31 msg->callref);
32 reject_mo_call(msg->callref, GSM48_CAUSE_LOC_PRN_S_LU,
33 GSM48_CC_CAUSE_INVAL_MAND_INF);
34 call->gc_flag = 1;
35 return;
36 }
37 /* same speech-only restriction as in OsmoMSC's mncc_builtin */
38 if (msg->bearer_cap.transfer != GSM48_BCAP_ITCAP_SPEECH ||
39 msg->bearer_cap.mode != GSM48_BCAP_TMOD_CIRCUIT) {
40 syslog(LOG_ERR, "rejecting intsw call 0x%x: bad bearer cap",
41 msg->callref);
42 reject_mo_call(msg->callref, GSM48_CAUSE_LOC_PRN_S_LU,
43 GSM48_CC_CAUSE_BEARER_CA_UNAVAIL);
44 call->gc_flag = 1;
45 return;
46 }
47 mt = create_new_mt_call();
48 if (!mt) {
49 syslog(LOG_ERR,
50 "rejecting intsw call 0x%x: no memory for MT call",
51 msg->callref);
52 reject_mo_call(msg->callref, GSM48_CAUSE_LOC_PRN_S_LU,
53 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
54 call->gc_flag = 1;
55 return;
56 }
57 syslog(LOG_DEBUG, "intsw: MO=0x%x MT=0x%x", call->callref, mt->callref);
58 call->other_leg = mt;
59 mt->other_leg = call;
60 /* send call proceeding */
61 bzero(&callproc, sizeof(struct gsm_mncc));
62 callproc.msg_type = MNCC_CALL_PROC_REQ;
63 callproc.callref = call->callref;
64 send_mncc_to_gsm(&callproc, sizeof(struct gsm_mncc));
65 /* turn MNCC_SETUP_IND into MNCC_SETUP_REQ for MT */
66 msg->msg_type = MNCC_SETUP_REQ;
67 msg->callref = mt->callref;
68 msg->imsi[0] = '\0';
69 send_mncc_to_gsm(msg, sizeof(struct gsm_mncc));
70 }
71
72 static void
73 handle_setup_cnf(call, msg)
74 struct gsm_call *call;
75 struct gsm_mncc *msg;
76 {
77 struct gsm_mncc ack;
78 struct gsm_mncc_bridge bridge;
79
80 /* acknowledge connect */
81 bzero(&ack, sizeof(struct gsm_mncc));
82 ack.msg_type = MNCC_SETUP_COMPL_REQ;
83 ack.callref = call->callref;
84 send_mncc_to_gsm(&ack, sizeof(struct gsm_mncc));
85 /* do we have the far end? */
86 if (!call->other_leg) {
87 syslog(LOG_ERR, "intsw: missing other leg for MNCC_SETUP_CNF");
88 return;
89 }
90 syslog(LOG_DEBUG, "MNCC_SETUP_CNF from 0x%x to 0x%x", call->callref,
91 call->other_leg->callref);
92 msg->msg_type = MNCC_SETUP_RSP;
93 msg->callref = call->other_leg->callref;
94 send_mncc_to_gsm(msg, sizeof(struct gsm_mncc));
95 /* bridge TCH */
96 bzero(&bridge, sizeof(struct gsm_mncc_bridge));
97 bridge.msg_type = MNCC_BRIDGE;
98 bridge.callref[0] = call->callref;
99 bridge.callref[1] = call->other_leg->callref;
100 send_mncc_to_gsm(&bridge, sizeof(struct gsm_mncc_bridge));
101 }
102
103 static void
104 forward_to_remote(call, msg, new_msg_type)
105 struct gsm_call *call;
106 struct gsm_mncc *msg;
107 uint32_t new_msg_type;
108 {
109 if (!call->other_leg) {
110 syslog(LOG_ERR, "intsw: missing other leg for msg forwarding");
111 /* drop it like OsmoMSC's mncc_builtin does */
112 return;
113 }
114 msg->msg_type = new_msg_type;
115 msg->callref = call->other_leg->callref;
116 send_mncc_to_gsm(msg, sizeof(struct gsm_mncc));
117 }
118
119 static void
120 handle_disconnect(call, msg)
121 struct gsm_call *call;
122 struct gsm_mncc *msg;
123 {
124 struct gsm_call *remote;
125
126 /* release on near end */
127 msg->msg_type = MNCC_REL_REQ;
128 send_mncc_to_gsm(msg, sizeof(struct gsm_mncc));
129 /* disconnect on far end */
130 remote = call->other_leg;
131 if (!remote) {
132 syslog(LOG_ERR, "intsw: missing other leg for MNCC_DISC_IND");
133 return;
134 }
135 syslog(LOG_DEBUG, "MNCC_DISC_IND from 0x%x to 0x%x", call->callref,
136 remote->callref);
137 msg->msg_type = MNCC_DISC_REQ;
138 msg->callref = remote->callref;
139 send_mncc_to_gsm(msg, sizeof(struct gsm_mncc));
140 /* sever the end-to-end association */
141 call->other_leg = 0;
142 remote->other_leg = 0;
143 }
144
145 static void
146 handle_release(call, msg)
147 struct gsm_call *call;
148 struct gsm_mncc *msg;
149 {
150 struct gsm_call *remote;
151
152 /* do we have a far end? */
153 remote = call->other_leg;
154 /* free the near end */
155 call->gc_flag = 1;
156 /* if no remote, nothing more to do */
157 if (!remote)
158 return;
159 syslog(LOG_DEBUG, "release with remote: from 0x%x to 0x%x",
160 call->callref, remote->callref);
161 /* send them a release request */
162 msg->msg_type = MNCC_REL_REQ;
163 msg->callref = remote->callref;
164 send_mncc_to_gsm(msg, sizeof(struct gsm_mncc));
165 /* sever the end-to-end association */
166 remote->other_leg = 0;
167 }
168
169 void
170 internal_switch_mncc(call, msg)
171 struct gsm_call *call;
172 struct gsm_mncc *msg;
173 {
174 switch (msg->msg_type) {
175 case MNCC_SETUP_CNF:
176 handle_setup_cnf(call, msg);
177 return;
178 case MNCC_ALERT_IND:
179 forward_to_remote(call, msg, MNCC_ALERT_REQ);
180 return;
181 case MNCC_NOTIFY_IND:
182 forward_to_remote(call, msg, MNCC_NOTIFY_REQ);
183 return;
184 case MNCC_USERINFO_IND:
185 forward_to_remote(call, msg, MNCC_USERINFO_REQ);
186 return;
187 case MNCC_DISC_IND:
188 handle_disconnect(call, msg);
189 return;
190 case MNCC_START_DTMF_IND:
191 msg->msg_type = MNCC_START_DTMF_REJ;
192 mncc_set_cause(msg, GSM48_CAUSE_LOC_PRN_S_LU,
193 GSM48_CC_CAUSE_SERV_OPT_UNIMPL);
194 send_mncc_to_gsm(msg, sizeof(struct gsm_mncc));
195 return;
196 case MNCC_STOP_DTMF_IND:
197 msg->msg_type = MNCC_STOP_DTMF_RSP;
198 send_mncc_to_gsm(msg, sizeof(struct gsm_mncc));
199 return;
200 case MNCC_MODIFY_IND:
201 msg->msg_type = MNCC_MODIFY_REJ;
202 mncc_set_cause(msg, GSM48_CAUSE_LOC_PRN_S_LU,
203 GSM48_CC_CAUSE_SERV_OPT_UNIMPL);
204 send_mncc_to_gsm(msg, sizeof(struct gsm_mncc));
205 return;
206 case MNCC_HOLD_IND:
207 msg->msg_type = MNCC_HOLD_REJ;
208 mncc_set_cause(msg, GSM48_CAUSE_LOC_PRN_S_LU,
209 GSM48_CC_CAUSE_SERV_OPT_UNIMPL);
210 send_mncc_to_gsm(msg, sizeof(struct gsm_mncc));
211 return;
212 case MNCC_RETRIEVE_IND:
213 msg->msg_type = MNCC_RETRIEVE_REJ;
214 mncc_set_cause(msg, GSM48_CAUSE_LOC_PRN_S_LU,
215 GSM48_CC_CAUSE_SERV_OPT_UNIMPL);
216 send_mncc_to_gsm(msg, sizeof(struct gsm_mncc));
217 return;
218 case MNCC_SETUP_COMPL_IND:
219 case MNCC_CALL_CONF_IND:
220 /* no handling needed */
221 return;
222 case MNCC_REL_IND:
223 case MNCC_REJ_IND:
224 handle_release(call, msg);
225 return;
226 case MNCC_REL_CNF:
227 call->gc_flag = 1;
228 return;
229 default:
230 syslog(LOG_ERR, "%s unhandled for internal switch",
231 mncc_msg_name(msg->msg_type));
232 }
233 }