FreeCalypso > hg > themwi-interim
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 } |