FreeCalypso > hg > themwi-interim
comparison mtctest/sig_handler.c @ 5:e7b192a5dee5
mtctest: initial import from old ThemWi
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sun, 09 Jun 2024 00:58:38 +0000 |
parents | |
children | 33d8b3177540 |
comparison
equal
deleted
inserted
replaced
4:ce450869db09 | 5:e7b192a5dee5 |
---|---|
1 /* | |
2 * In this module we handle all incoming messages from MNCC, | |
3 * printing all of them and generating protocol-required responses | |
4 * for some. | |
5 */ | |
6 | |
7 #include <sys/types.h> | |
8 #include <sys/time.h> | |
9 #include <sys/socket.h> | |
10 #include <stdio.h> | |
11 #include <stdint.h> | |
12 #include <stdlib.h> | |
13 #include <string.h> | |
14 #include <strings.h> | |
15 #include "../include/mncc.h" | |
16 #include "../include/gsm48_const.h" | |
17 | |
18 extern int disconnect_mode; | |
19 extern struct sockaddr_storage dummy_rtp_endp; | |
20 extern struct timeval cur_event_time; | |
21 | |
22 static void | |
23 print_bearer_cap(bcap) | |
24 struct gsm_mncc_bearer_cap *bcap; | |
25 { | |
26 int i, sv; | |
27 | |
28 printf("Bearer cap: itcap=%d tmod=%d coding=%d rrq=%d\n", | |
29 bcap->transfer, bcap->mode, bcap->coding, bcap->radio); | |
30 printf(" speech: CTM=%d sv", bcap->speech_ctm); | |
31 for (i = 0; i < 8; i++) { | |
32 sv = bcap->speech_ver[i]; | |
33 if (sv < 0) | |
34 break; | |
35 printf(" %d", sv); | |
36 } | |
37 putchar('\n'); | |
38 printf(" data: ra=%d sig=%d async=%d nstop=%d ndata=%d\n", | |
39 bcap->data.rate_adaption, bcap->data.sig_access, | |
40 bcap->data.async, bcap->data.nr_stop_bits, | |
41 bcap->data.nr_data_bits); | |
42 printf(" urate=%d par=%d irate=%d transp=%d mtype=%d\n", | |
43 bcap->data.user_rate, bcap->data.parity, | |
44 bcap->data.interm_rate, bcap->data.transp, | |
45 bcap->data.modem_type); | |
46 } | |
47 | |
48 static void | |
49 print_cc_cap(cc) | |
50 struct gsm_mncc_cccap *cc; | |
51 { | |
52 printf("CC capabilities: DTMF=%d PCP=%d\n", cc->dtmf, cc->pcp); | |
53 } | |
54 | |
55 static void | |
56 print_cause(cause) | |
57 struct gsm_mncc_cause *cause; | |
58 { | |
59 int i; | |
60 | |
61 printf("Cause: loc=%d coding=%d value=%d", cause->location, | |
62 cause->coding, cause->value); | |
63 if (cause->rec) | |
64 printf(" rec=0x%02X", cause->rec_val); | |
65 for (i = 0; i < cause->diag_len; i++) { | |
66 if (!(i & 15)) { | |
67 putchar('\n'); | |
68 putchar(' '); | |
69 } | |
70 printf(" %02X", cause->diag[i] & 0xFF); | |
71 } | |
72 putchar('\n'); | |
73 } | |
74 | |
75 static void | |
76 print_progress(prog) | |
77 struct gsm_mncc_progress *prog; | |
78 { | |
79 printf("Progress: loc=%d coding=%d descr=0x%02X", prog->location, | |
80 prog->coding, prog->descr); | |
81 } | |
82 | |
83 static void | |
84 print_useruser(uu) | |
85 struct gsm_mncc_useruser *uu; | |
86 { | |
87 printf("User-User IE: proto=0x%02X\n", uu->proto); | |
88 /* dump to be implemented if and when we actually get a UU somewhere */ | |
89 } | |
90 | |
91 static void | |
92 print_keypad(kp) | |
93 int kp; | |
94 { | |
95 if (kp >= '!' && kp <= '~') | |
96 printf("Keypad code: %c\n", kp); | |
97 else | |
98 printf("Keypad code: 0x%02X\n", kp); | |
99 } | |
100 | |
101 static void | |
102 print_facility(fac) | |
103 struct gsm_mncc_facility *fac; | |
104 { | |
105 int i; | |
106 | |
107 printf("Facility IE: %d byte(s)", fac->len); | |
108 for (i = 0; i < fac->len; i++) { | |
109 if (!(i & 15)) { | |
110 putchar('\n'); | |
111 putchar(' '); | |
112 } | |
113 printf(" %02X", fac->info[i] & 0xFF); | |
114 } | |
115 putchar('\n'); | |
116 } | |
117 | |
118 static void | |
119 print_ssver(ssv) | |
120 struct gsm_mncc_ssversion *ssv; | |
121 { | |
122 int i; | |
123 | |
124 printf("SS version IE: %d byte(s)", ssv->len); | |
125 for (i = 0; i < ssv->len; i++) { | |
126 if (!(i & 15)) { | |
127 putchar('\n'); | |
128 putchar(' '); | |
129 } | |
130 printf(" %02X", ssv->info[i] & 0xFF); | |
131 } | |
132 putchar('\n'); | |
133 } | |
134 | |
135 static void | |
136 print_fields(msg) | |
137 struct gsm_mncc *msg; | |
138 { | |
139 if (msg->fields & MNCC_F_BEARER_CAP) | |
140 print_bearer_cap(&msg->bearer_cap); | |
141 if (msg->fields & MNCC_F_CCCAP) | |
142 print_cc_cap(&msg->cccap); | |
143 if (msg->fields & MNCC_F_CAUSE) | |
144 print_cause(&msg->cause); | |
145 if (msg->fields & MNCC_F_PROGRESS) | |
146 print_progress(&msg->progress); | |
147 if (msg->fields & MNCC_F_USERUSER) | |
148 print_useruser(&msg->useruser); | |
149 if (msg->more) | |
150 printf("More data flag set\n"); | |
151 if (msg->fields & MNCC_F_KEYPAD) | |
152 print_keypad(msg->keypad); | |
153 if (msg->fields & MNCC_F_FACILITY) | |
154 print_facility(&msg->facility); | |
155 if (msg->fields & MNCC_F_SSVERSION) | |
156 print_ssver(&msg->ssversion); | |
157 } | |
158 | |
159 static void | |
160 print_sdp(sdp) | |
161 char *sdp; | |
162 { | |
163 char *cp, *ep, *np; | |
164 | |
165 for (cp = sdp; *cp; cp = np) { | |
166 ep = index(cp, '\n'); | |
167 if (ep) { | |
168 *ep = '\0'; | |
169 np = ep + 1; | |
170 } else | |
171 np = 0; | |
172 ep = index(cp, '\r'); | |
173 if (ep) | |
174 *ep = '\0'; | |
175 printf("%s %s\n", cp == sdp ? "SDP:" : " ", cp); | |
176 } | |
177 } | |
178 | |
179 static void | |
180 send_connect_ack() | |
181 { | |
182 struct gsm_mncc ack; | |
183 | |
184 printf("Sending connect ack\n"); | |
185 bzero(&ack, sizeof(struct gsm_mncc)); | |
186 ack.msg_type = MNCC_SETUP_COMPL_REQ; | |
187 ack.callref = 1; | |
188 send_mncc_to_gsm(&ack, sizeof(struct gsm_mncc)); | |
189 } | |
190 | |
191 static void | |
192 send_rtp_connect() | |
193 { | |
194 struct gsm_mncc_rtp rtp; | |
195 | |
196 printf("Sending MNCC_RTP_CONNECT\n"); | |
197 bzero(&rtp, sizeof(struct gsm_mncc_rtp)); | |
198 rtp.msg_type = MNCC_RTP_CONNECT; | |
199 rtp.callref = 1; | |
200 bcopy(&dummy_rtp_endp, &rtp.addr, sizeof(struct sockaddr_storage)); | |
201 send_mncc_to_gsm(&rtp, sizeof(struct gsm_mncc_rtp)); | |
202 } | |
203 | |
204 static void | |
205 handle_dtmf_time() | |
206 { | |
207 static struct timeval last_dtmf_time; | |
208 struct timeval delta; | |
209 unsigned ms; | |
210 | |
211 if (timerisset(&last_dtmf_time) && | |
212 timercmp(&cur_event_time, &last_dtmf_time, >)) { | |
213 timersub(&cur_event_time, &last_dtmf_time, &delta); | |
214 if (delta.tv_sec >= 2) | |
215 printf("Time since last DTMF event: %u s\n", | |
216 (unsigned) delta.tv_sec); | |
217 else { | |
218 ms = delta.tv_sec * 1000 + delta.tv_usec / 1000; | |
219 printf("Time since last DTMF event: %u ms\n", ms); | |
220 } | |
221 } | |
222 bcopy(&cur_event_time, &last_dtmf_time, sizeof(struct timeval)); | |
223 } | |
224 | |
225 static void | |
226 handle_signaling_msg(msg, msglen) | |
227 struct gsm_mncc *msg; | |
228 unsigned msglen; | |
229 { | |
230 if (msglen != sizeof(struct gsm_mncc)) { | |
231 fprintf(stderr, | |
232 "error: Rx MNCC message type 0x%x has wrong length\n", | |
233 msg->msg_type); | |
234 exit(1); | |
235 } | |
236 if (msg->callref != 1) { | |
237 fprintf(stderr, | |
238 "error: Rx MNCC message type 0x%x has unexpected callref 0x%x\n", | |
239 msg->msg_type, msg->callref); | |
240 exit(1); | |
241 } | |
242 switch (msg->msg_type) { | |
243 case MNCC_SETUP_CNF: | |
244 printf("MNCC_SETUP_CNF: call is answered\n"); | |
245 print_fields(msg); | |
246 print_sdp(msg->sdp); | |
247 send_rtp_connect(); | |
248 send_connect_ack(); | |
249 return; | |
250 case MNCC_CALL_CONF_IND: | |
251 printf("MNCC_CALL_CONF_IND: call is confirmed\n"); | |
252 print_fields(msg); | |
253 print_sdp(msg->sdp); | |
254 return; | |
255 case MNCC_ALERT_IND: | |
256 printf("MNCC_ALERT_IND: call is alerting\n"); | |
257 print_fields(msg); | |
258 print_sdp(msg->sdp); | |
259 return; | |
260 case MNCC_NOTIFY_IND: | |
261 printf("NNCC_NOTIFY_IND: NOTIFY byte from MS: 0x%02X\n", | |
262 msg->notify); | |
263 return; | |
264 case MNCC_DISC_IND: | |
265 printf("MNCC_DISC_IND: MS initiates disconnect\n"); | |
266 print_fields(msg); | |
267 disconnect_mode = 1; | |
268 printf("Responding with release request\n"); | |
269 msg->msg_type = MNCC_REL_REQ; | |
270 send_mncc_to_gsm(msg, sizeof(struct gsm_mncc)); | |
271 return; | |
272 case MNCC_FACILITY_IND: | |
273 printf("MNCC_FACILITY_IND: call-related SS from MS\n"); | |
274 print_fields(msg); | |
275 return; | |
276 case MNCC_START_DTMF_IND: | |
277 printf("MNCC_START_DTMF_IND: MS sending DTMF start\n"); | |
278 print_fields(msg); | |
279 handle_dtmf_time(); | |
280 if (msg->fields & MNCC_F_KEYPAD && | |
281 is_valid_dtmf_digit(msg->keypad)) { | |
282 printf("Responding with ACK\n"); | |
283 msg->msg_type = MNCC_START_DTMF_RSP; | |
284 } else { | |
285 printf("Responding with Reject\n"); | |
286 msg->msg_type = MNCC_START_DTMF_REJ; | |
287 mncc_set_cause(msg, GSM48_CAUSE_LOC_PRN_S_LU, | |
288 GSM48_CC_CAUSE_INVAL_MAND_INF); | |
289 } | |
290 send_mncc_to_gsm(msg, sizeof(struct gsm_mncc)); | |
291 return; | |
292 case MNCC_STOP_DTMF_IND: | |
293 printf("MNCC_STOP_DTMF_IND: MS sending DTMF stop\n"); | |
294 handle_dtmf_time(); | |
295 msg->msg_type = MNCC_STOP_DTMF_RSP; | |
296 send_mncc_to_gsm(msg, sizeof(struct gsm_mncc)); | |
297 return; | |
298 case MNCC_MODIFY_IND: | |
299 printf("MNCC_MODIFY_IND: MS requests call modification\n"); | |
300 print_fields(msg); | |
301 msg->msg_type = MNCC_MODIFY_REJ; | |
302 mncc_set_cause(msg, GSM48_CAUSE_LOC_PRN_S_LU, | |
303 GSM48_CC_CAUSE_SERV_OPT_UNIMPL); | |
304 send_mncc_to_gsm(msg, sizeof(struct gsm_mncc)); | |
305 return; | |
306 case MNCC_HOLD_IND: | |
307 printf("MNCC_HOLD_IND: MS requests call hold\n"); | |
308 msg->msg_type = MNCC_HOLD_CNF; | |
309 send_mncc_to_gsm(msg, sizeof(struct gsm_mncc)); | |
310 return; | |
311 case MNCC_RETRIEVE_IND: | |
312 printf("MNCC_RETRIEVE_IND: MS requests call retrieve\n"); | |
313 send_rtp_connect(); | |
314 msg->msg_type = MNCC_RETRIEVE_CNF; | |
315 send_mncc_to_gsm(msg, sizeof(struct gsm_mncc)); | |
316 return; | |
317 case MNCC_USERINFO_IND: | |
318 printf("MNCC_USERINFO_IND: user-user info\n"); | |
319 print_fields(msg); | |
320 return; | |
321 case MNCC_REL_IND: | |
322 printf("MNCC_REL_IND: final release\n"); | |
323 print_fields(msg); | |
324 exit(0); | |
325 case MNCC_REL_CNF: | |
326 printf("MNCC_REL_CNF: final release in response to request\n"); | |
327 print_fields(msg); | |
328 exit(0); | |
329 case MNCC_REJ_IND: | |
330 printf("MNCC_REJ_IND: MT call rejected\n"); | |
331 print_fields(msg); | |
332 exit(0); | |
333 } | |
334 } | |
335 | |
336 static void | |
337 handle_rtp_msg(msg, msglen) | |
338 struct gsm_mncc_rtp *msg; | |
339 unsigned msglen; | |
340 { | |
341 if (msglen != sizeof(struct gsm_mncc_rtp)) { | |
342 fprintf(stderr, | |
343 "error: Rx MNCC message type 0x%x has wrong length\n", | |
344 msg->msg_type); | |
345 exit(1); | |
346 } | |
347 if (msg->callref != 1) { | |
348 fprintf(stderr, | |
349 "error: Rx MNCC message type 0x%x has unexpected callref 0x%x\n", | |
350 msg->msg_type, msg->callref); | |
351 exit(1); | |
352 } | |
353 switch (msg->msg_type) { | |
354 case MNCC_RTP_CREATE: | |
355 printf("MNCC_RTP_CREATE: RTP info from MSC\n"); | |
356 printf("payload_type=0x%x payload_msg_type=0x%x\n", | |
357 msg->payload_type, msg->payload_msg_type); | |
358 print_sdp(msg->sdp); | |
359 return; | |
360 case MNCC_RTP_CONNECT: | |
361 printf("MNCC_RTP_CONNECT: error response\n"); | |
362 return; | |
363 case MNCC_RTP_FREE: | |
364 printf("MNCC_RTP_FREE: bogon\n"); | |
365 return; | |
366 } | |
367 } | |
368 | |
369 void | |
370 msg_from_mncc(msg, msglen) | |
371 union mncc_msg *msg; | |
372 unsigned msglen; | |
373 { | |
374 switch (msg->msg_type) { | |
375 case MNCC_SETUP_CNF: | |
376 case MNCC_CALL_CONF_IND: | |
377 case MNCC_ALERT_IND: | |
378 case MNCC_NOTIFY_IND: | |
379 case MNCC_DISC_IND: | |
380 case MNCC_FACILITY_IND: | |
381 case MNCC_START_DTMF_IND: | |
382 case MNCC_STOP_DTMF_IND: | |
383 case MNCC_MODIFY_IND: | |
384 case MNCC_HOLD_IND: | |
385 case MNCC_RETRIEVE_IND: | |
386 case MNCC_USERINFO_IND: | |
387 case MNCC_REL_IND: | |
388 case MNCC_REL_CNF: | |
389 case MNCC_REJ_IND: | |
390 handle_signaling_msg(msg, msglen); | |
391 return; | |
392 case MNCC_RTP_CREATE: | |
393 case MNCC_RTP_CONNECT: | |
394 case MNCC_RTP_FREE: | |
395 handle_rtp_msg(msg, msglen); | |
396 return; | |
397 default: | |
398 fprintf(stderr, | |
399 "error: received unexpected MNCC message type 0x%x\n", | |
400 msg->msg_type); | |
401 exit(1); | |
402 } | |
403 } |