FreeCalypso > hg > themwi-interim
view mtctest/sig_handler.c @ 11:aa2ba9b432af
mtctest: implement play and play-stop commands
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sun, 09 Jun 2024 04:32:57 +0000 |
parents | 0ec938ed530b |
children |
line wrap: on
line source
/* * In this module we handle all incoming messages from MNCC, * printing all of them and generating protocol-required responses * for some. */ #include <sys/types.h> #include <sys/time.h> #include <sys/socket.h> #include <stdio.h> #include <stdint.h> #include <stdlib.h> #include <string.h> #include <strings.h> #include <themwi/rtp/rtp_alloc_simple.h> #include "../include/mncc.h" #include "../include/gsm48_const.h" extern int disconnect_mode; extern struct rtp_alloc_simple rtp_info; extern struct timeval cur_event_time; int got_msc_rtp_info; struct sockaddr_storage msc_rtp_addr; uint8_t rtp_payload_type; static void print_bearer_cap(bcap) struct gsm_mncc_bearer_cap *bcap; { int i, sv; printf("Bearer cap: itcap=%d tmod=%d coding=%d rrq=%d\n", bcap->transfer, bcap->mode, bcap->coding, bcap->radio); printf(" speech: CTM=%d sv", bcap->speech_ctm); for (i = 0; i < 8; i++) { sv = bcap->speech_ver[i]; if (sv < 0) break; printf(" %d", sv); } putchar('\n'); printf(" data: ra=%d sig=%d async=%d nstop=%d ndata=%d\n", bcap->data.rate_adaption, bcap->data.sig_access, bcap->data.async, bcap->data.nr_stop_bits, bcap->data.nr_data_bits); printf(" urate=%d par=%d irate=%d transp=%d mtype=%d\n", bcap->data.user_rate, bcap->data.parity, bcap->data.interm_rate, bcap->data.transp, bcap->data.modem_type); } static void print_cc_cap(cc) struct gsm_mncc_cccap *cc; { printf("CC capabilities: DTMF=%d PCP=%d\n", cc->dtmf, cc->pcp); } static void print_cause(cause) struct gsm_mncc_cause *cause; { int i; printf("Cause: loc=%d coding=%d value=%d", cause->location, cause->coding, cause->value); if (cause->rec) printf(" rec=0x%02X", cause->rec_val); for (i = 0; i < cause->diag_len; i++) { if (!(i & 15)) { putchar('\n'); putchar(' '); } printf(" %02X", cause->diag[i] & 0xFF); } putchar('\n'); } static void print_progress(prog) struct gsm_mncc_progress *prog; { printf("Progress: loc=%d coding=%d descr=0x%02X", prog->location, prog->coding, prog->descr); } static void print_useruser(uu) struct gsm_mncc_useruser *uu; { printf("User-User IE: proto=0x%02X\n", uu->proto); /* dump to be implemented if and when we actually get a UU somewhere */ } static void print_keypad(kp) int kp; { if (kp >= '!' && kp <= '~') printf("Keypad code: %c\n", kp); else printf("Keypad code: 0x%02X\n", kp); } static void print_facility(fac) struct gsm_mncc_facility *fac; { int i; printf("Facility IE: %d byte(s)", fac->len); for (i = 0; i < fac->len; i++) { if (!(i & 15)) { putchar('\n'); putchar(' '); } printf(" %02X", fac->info[i] & 0xFF); } putchar('\n'); } static void print_ssver(ssv) struct gsm_mncc_ssversion *ssv; { int i; printf("SS version IE: %d byte(s)", ssv->len); for (i = 0; i < ssv->len; i++) { if (!(i & 15)) { putchar('\n'); putchar(' '); } printf(" %02X", ssv->info[i] & 0xFF); } putchar('\n'); } static void print_fields(msg) struct gsm_mncc *msg; { if (msg->fields & MNCC_F_BEARER_CAP) print_bearer_cap(&msg->bearer_cap); if (msg->fields & MNCC_F_CCCAP) print_cc_cap(&msg->cccap); if (msg->fields & MNCC_F_CAUSE) print_cause(&msg->cause); if (msg->fields & MNCC_F_PROGRESS) print_progress(&msg->progress); if (msg->fields & MNCC_F_USERUSER) print_useruser(&msg->useruser); if (msg->more) printf("More data flag set\n"); if (msg->fields & MNCC_F_KEYPAD) print_keypad(msg->keypad); if (msg->fields & MNCC_F_FACILITY) print_facility(&msg->facility); if (msg->fields & MNCC_F_SSVERSION) print_ssver(&msg->ssversion); } static void print_sdp(sdp) char *sdp; { char *cp, *ep, *np; for (cp = sdp; *cp; cp = np) { ep = index(cp, '\n'); if (ep) { *ep = '\0'; np = ep + 1; } else np = 0; ep = index(cp, '\r'); if (ep) *ep = '\0'; printf("%s %s\n", cp == sdp ? "SDP:" : " ", cp); } } static void send_connect_ack() { struct gsm_mncc ack; printf("Sending connect ack\n"); bzero(&ack, sizeof(struct gsm_mncc)); ack.msg_type = MNCC_SETUP_COMPL_REQ; ack.callref = 1; send_mncc_to_gsm(&ack, sizeof(struct gsm_mncc)); } static void send_rtp_connect() { struct gsm_mncc_rtp rtp; printf("Sending MNCC_RTP_CONNECT\n"); bzero(&rtp, sizeof(struct gsm_mncc_rtp)); rtp.msg_type = MNCC_RTP_CONNECT; rtp.callref = 1; bcopy(&rtp_info.gsm_addr, &rtp.addr, sizeof(struct sockaddr_storage)); send_mncc_to_gsm(&rtp, sizeof(struct gsm_mncc_rtp)); } static void handle_dtmf_time() { static struct timeval last_dtmf_time; struct timeval delta; unsigned ms; if (timerisset(&last_dtmf_time) && timercmp(&cur_event_time, &last_dtmf_time, >)) { timersub(&cur_event_time, &last_dtmf_time, &delta); if (delta.tv_sec >= 2) printf("Time since last DTMF event: %u s\n", (unsigned) delta.tv_sec); else { ms = delta.tv_sec * 1000 + delta.tv_usec / 1000; printf("Time since last DTMF event: %u ms\n", ms); } } bcopy(&cur_event_time, &last_dtmf_time, sizeof(struct timeval)); } static void handle_signaling_msg(msg, msglen) struct gsm_mncc *msg; unsigned msglen; { if (msglen != sizeof(struct gsm_mncc)) { fprintf(stderr, "error: Rx MNCC message type 0x%x has wrong length\n", msg->msg_type); exit(1); } if (msg->callref != 1) { fprintf(stderr, "error: Rx MNCC message type 0x%x has unexpected callref 0x%x\n", msg->msg_type, msg->callref); exit(1); } switch (msg->msg_type) { case MNCC_SETUP_CNF: printf("MNCC_SETUP_CNF: call is answered\n"); print_fields(msg); print_sdp(msg->sdp); send_rtp_connect(); send_connect_ack(); return; case MNCC_CALL_CONF_IND: printf("MNCC_CALL_CONF_IND: call is confirmed\n"); print_fields(msg); print_sdp(msg->sdp); return; case MNCC_ALERT_IND: printf("MNCC_ALERT_IND: call is alerting\n"); print_fields(msg); print_sdp(msg->sdp); return; case MNCC_NOTIFY_IND: printf("NNCC_NOTIFY_IND: NOTIFY byte from MS: 0x%02X\n", msg->notify); return; case MNCC_DISC_IND: printf("MNCC_DISC_IND: MS initiates disconnect\n"); print_fields(msg); disconnect_mode = 1; printf("Responding with release request\n"); msg->msg_type = MNCC_REL_REQ; send_mncc_to_gsm(msg, sizeof(struct gsm_mncc)); return; case MNCC_FACILITY_IND: printf("MNCC_FACILITY_IND: call-related SS from MS\n"); print_fields(msg); return; case MNCC_START_DTMF_IND: printf("MNCC_START_DTMF_IND: MS sending DTMF start\n"); print_fields(msg); handle_dtmf_time(); if (msg->fields & MNCC_F_KEYPAD && is_valid_dtmf_digit(msg->keypad)) { printf("Responding with ACK\n"); msg->msg_type = MNCC_START_DTMF_RSP; } else { printf("Responding with Reject\n"); msg->msg_type = MNCC_START_DTMF_REJ; mncc_set_cause(msg, GSM48_CAUSE_LOC_PRN_S_LU, GSM48_CC_CAUSE_INVAL_MAND_INF); } send_mncc_to_gsm(msg, sizeof(struct gsm_mncc)); return; case MNCC_STOP_DTMF_IND: printf("MNCC_STOP_DTMF_IND: MS sending DTMF stop\n"); handle_dtmf_time(); msg->msg_type = MNCC_STOP_DTMF_RSP; send_mncc_to_gsm(msg, sizeof(struct gsm_mncc)); return; case MNCC_MODIFY_IND: printf("MNCC_MODIFY_IND: MS requests call modification\n"); print_fields(msg); msg->msg_type = MNCC_MODIFY_REJ; mncc_set_cause(msg, GSM48_CAUSE_LOC_PRN_S_LU, GSM48_CC_CAUSE_SERV_OPT_UNIMPL); send_mncc_to_gsm(msg, sizeof(struct gsm_mncc)); return; case MNCC_HOLD_IND: printf("MNCC_HOLD_IND: MS requests call hold\n"); msg->msg_type = MNCC_HOLD_CNF; send_mncc_to_gsm(msg, sizeof(struct gsm_mncc)); return; case MNCC_RETRIEVE_IND: printf("MNCC_RETRIEVE_IND: MS requests call retrieve\n"); send_rtp_connect(); msg->msg_type = MNCC_RETRIEVE_CNF; send_mncc_to_gsm(msg, sizeof(struct gsm_mncc)); return; case MNCC_USERINFO_IND: printf("MNCC_USERINFO_IND: user-user info\n"); print_fields(msg); return; case MNCC_REL_IND: printf("MNCC_REL_IND: final release\n"); print_fields(msg); exit(0); case MNCC_REL_CNF: printf("MNCC_REL_CNF: final release in response to request\n"); print_fields(msg); exit(0); case MNCC_REJ_IND: printf("MNCC_REJ_IND: MT call rejected\n"); print_fields(msg); exit(0); } } static void handle_rtp_msg(msg, msglen) struct gsm_mncc_rtp *msg; unsigned msglen; { if (msglen != sizeof(struct gsm_mncc_rtp)) { fprintf(stderr, "error: Rx MNCC message type 0x%x has wrong length\n", msg->msg_type); exit(1); } if (msg->callref != 1) { fprintf(stderr, "error: Rx MNCC message type 0x%x has unexpected callref 0x%x\n", msg->msg_type, msg->callref); exit(1); } switch (msg->msg_type) { case MNCC_RTP_CREATE: printf("MNCC_RTP_CREATE: RTP info from MSC\n"); printf("payload_type=0x%x payload_msg_type=0x%x\n", msg->payload_type, msg->payload_msg_type); print_sdp(msg->sdp); got_msc_rtp_info = 1; bcopy(&msg->addr, &msc_rtp_addr, sizeof(struct sockaddr_storage)); rtp_payload_type = msg->payload_type; return; case MNCC_RTP_CONNECT: printf("MNCC_RTP_CONNECT: error response\n"); return; case MNCC_RTP_FREE: printf("MNCC_RTP_FREE: bogon\n"); return; } } void msg_from_mncc(msg, msglen) union mncc_msg *msg; unsigned msglen; { switch (msg->msg_type) { case MNCC_SETUP_CNF: case MNCC_CALL_CONF_IND: case MNCC_ALERT_IND: case MNCC_NOTIFY_IND: case MNCC_DISC_IND: case MNCC_FACILITY_IND: case MNCC_START_DTMF_IND: case MNCC_STOP_DTMF_IND: case MNCC_MODIFY_IND: case MNCC_HOLD_IND: case MNCC_RETRIEVE_IND: case MNCC_USERINFO_IND: case MNCC_REL_IND: case MNCC_REL_CNF: case MNCC_REJ_IND: handle_signaling_msg(msg, msglen); return; case MNCC_RTP_CREATE: case MNCC_RTP_CONNECT: case MNCC_RTP_FREE: handle_rtp_msg(msg, msglen); return; default: fprintf(stderr, "error: received unexpected MNCC message type 0x%x\n", msg->msg_type); exit(1); } }