/* Point-to-Point (PP) Short Message Service (SMS) * Support on Mobile Radio Interface * 3GPP TS 04.11 version 7.1.0 Release 1998 / ETSI TS 100 942 V7.1.0 */ /* (C) 2008 by Daniel Willmann * (C) 2009 by Harald Welte * (C) 2010-2012 by Holger Hans Peter Freyther * (C) 2010 by On-Waves * (C) 2011 by Andreas Eversberg * * All Rights Reserved * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * */ #include #include #include #include #include #include #include "bscconfig.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef BUILD_SMPP #include "smpp_smsc.h" extern int smpp_try_deliver(struct gsm_sms *sms, struct gsm_subscriber_connection *conn); #endif void *tall_gsms_ctx; static uint32_t new_callref = 0x40000001; struct gsm_sms *sms_alloc(void) { return talloc_zero(tall_gsms_ctx, struct gsm_sms); } void sms_free(struct gsm_sms *sms) { /* drop references to subscriber structure */ if (sms->receiver) subscr_put(sms->receiver); #ifdef BUILD_SMPP if (sms->smpp.esme) smpp_esme_put(sms->smpp.esme); #endif talloc_free(sms); } struct gsm_sms *sms_from_text(struct gsm_subscriber *receiver, struct gsm_subscriber *sender, int dcs, const char *text) { struct gsm_sms *sms = sms_alloc(); if (!sms) return NULL; sms->type = GSM_SMS_DELIVER; sms->receiver = subscr_get(receiver); strncpy(sms->text, text, sizeof(sms->text)-1); strncpy(sms->src.addr, sender->extension, sizeof(sms->src.addr)-1); sms->reply_path_req = 0; sms->status_rep_req = 0; sms->ud_hdr_ind = 0; sms->protocol_id = 0; /* implicit */ sms->data_coding_scheme = dcs; strncpy(sms->dst.addr, receiver->extension, sizeof(sms->dst.addr)-1); /* Timestamps */ time(&sms->received_time); sms->valid_until = sms->received_time + SMS_DEFAULT_VALIDITY_PERIOD; /* Generate user_data */ sms->user_data_len = gsm_7bit_encode_n(sms->user_data, sizeof(sms->user_data), sms->text, NULL); return sms; } static void send_signal(int sig_no, struct gsm_trans *trans, struct gsm_sms *sms, int paging_result) { struct sms_signal_data sig; sig.trans = trans; sig.sms = sms; sig.paging_result = paging_result; osmo_signal_dispatch(SS_SMS, sig_no, &sig); } struct gsm_sms *gen_status_rep_from_deliver(struct gsm_network *net, struct gsm_sms *sms) { struct gsm_sms *report; report = sms_alloc(); if (!report) return NULL; /* This is a normal SMS */ report->type = GSM_SMS_STATUS_REP; /* Swap src and dst addresses */ report->src = sms->dst; report->dst = sms->src; report->receiver = subscr_get_by_extension(net, report->dst.addr); report->source = SMS_SOURCE_INT; report->received_time = sms->received_time; report->delivered_time = time(NULL); report->msg_ref = sms->msg_ref; report->protocol_id = sms->protocol_id; /* TODO: I'm not sure this is correct */ report->valid_until = report->delivered_time + SMS_DEFAULT_VALIDITY_PERIOD; return report; } static int send_status_rep(struct gsm_network *net, struct gsm_sms *sms) { struct gsm_sms *report; LOGP(DLSMS, LOGL_ERROR, "In with send_status_rep()\n"); report = gen_status_rep_from_deliver(net, sms); if (!report) return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER; /* store in the database for the queue */ if (db_sms_store(report) != 0) { LOGP(DLSMS, LOGL_ERROR, "Failed to store SMS in Database\n"); sms_free(report); return -1; } sms_free(report); sms_queue_trigger(net->sms_queue); return 0; } static int gsm411_sendmsg(struct gsm_subscriber_connection *conn, struct msgb *msg) { DEBUGP(DLSMS, "GSM4.11 TX %s\n", osmo_hexdump(msg->data, msg->len)); msg->l3h = msg->data; return gsm0808_submit_dtap(conn, msg, UM_SAPI_SMS, 1); } /* Prefix msg with a 04.08/04.11 CP header */ static int gsm411_cp_sendmsg(struct msgb *msg, struct gsm_trans *trans, uint8_t msg_type) { struct gsm48_hdr *gh; gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh)); /* Outgoing needs the highest bit set */ gh->proto_discr = trans->protocol | (trans->transaction_id<<4); gh->msg_type = msg_type; DEBUGP(DLSMS, "sending CP message (trans=%x)\n", trans->transaction_id); return gsm411_sendmsg(trans->conn, msg); } /* mm_send: receive MMCCSMS sap message from SMC */ static int gsm411_mm_send(struct gsm411_smc_inst *inst, int msg_type, struct msgb *msg, int cp_msg_type) { struct gsm_trans *trans = container_of(inst, struct gsm_trans, sms.smc_inst); int rc = 0; switch (msg_type) { case GSM411_MMSMS_EST_REQ: /* recycle msg */ rc = gsm411_smc_recv(inst, GSM411_MMSMS_EST_CNF, msg, 0); msgb_free(msg); /* upper layer does not free msg */ break; case GSM411_MMSMS_DATA_REQ: rc = gsm411_cp_sendmsg(msg, trans, cp_msg_type); break; case GSM411_MMSMS_REL_REQ: DEBUGP(DLSMS, "Got MMSMS_REL_REQ, destroying transaction.\n"); msgb_free(msg); trans_free(trans); break; default: LOGP(DLSMS, LOGL_NOTICE, "Unhandled MMCCSMS msg 0x%x\n", msg_type); msgb_free(msg); rc = -EINVAL; } return rc; } /* mm_send: receive MNCCSMS sap message from SMR */ int gsm411_mn_send(struct gsm411_smr_inst *inst, int msg_type, struct msgb *msg) { struct gsm_trans *trans = container_of(inst, struct gsm_trans, sms.smr_inst); /* forward to SMC */ return gsm411_smc_send(&trans->sms.smc_inst, msg_type, msg); } static int gsm340_rx_sms_submit(struct msgb *msg, struct gsm_sms *gsms) { if (db_sms_store(gsms) != 0) { LOGP(DLSMS, LOGL_ERROR, "Failed to store SMS in Database\n"); return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER; } /* dispatch a signal to tell higher level about it */ send_signal(S_SMS_SUBMITTED, NULL, gsms, 0); return 0; } /* generate a TPDU address field compliant with 03.40 sec. 9.1.2.5 */ static int gsm340_gen_addr_sub(uint8_t *oa, unsigned int oa_len, const struct gsm_sms_addr *src) { /* network specific, private numbering plan */ return gsm340_gen_address_field(oa, oa_len, src->ton, src->npi, src->addr); } /* generate a msgb containing an 03.40 9.2.2.1 SMS-DELIVER TPDU derived from * struct gsm_sms, returns total size of TPDU */ static int gsm340_gen_sms_deliver_tpdu(struct msgb *msg, struct gsm_sms *sms) { uint8_t *smsp; uint8_t oa[12]; /* max len per 03.40 */ uint8_t oa_len = 0; uint8_t octet_len; unsigned int old_msg_len = msg->len; /* generate first octet with masked bits */ smsp = msgb_put(msg, 1); /* TP-MTI (message type indicator) */ *smsp = GSM340_SMS_DELIVER_SC2MS; /* TP-MMS (more messages to send) */ if (0 /* FIXME */) *smsp |= 0x04; /* TP-SRI(deliver)/SRR(submit) */ if (sms->status_rep_req) *smsp |= 0x20; /* TP-UDHI (indicating TP-UD contains a header) */ if (sms->ud_hdr_ind) *smsp |= 0x40; /* generate originator address */ oa_len = gsm340_gen_addr_sub(oa, sizeof(oa), &sms->src); smsp = msgb_put(msg, oa_len); memcpy(smsp, oa, oa_len); /* generate TP-PID */ smsp = msgb_put(msg, 1); *smsp = sms->protocol_id; /* generate TP-DCS */ smsp = msgb_put(msg, 1); *smsp = sms->data_coding_scheme; /* generate TP-SCTS */ smsp = msgb_put(msg, 7); gsm340_gen_scts(smsp, sms->received_time); /* generate TP-UDL */ smsp = msgb_put(msg, 1); *smsp = sms->user_data_len; /* generate TP-UD */ switch (gsm338_get_sms_alphabet(sms->data_coding_scheme)) { case DCS_7BIT_DEFAULT: octet_len = sms->user_data_len*7/8; if (sms->user_data_len*7%8 != 0) octet_len++; /* Warning, user_data_len indicates the amount of septets * (characters), we need amount of octets occupied */ smsp = msgb_put(msg, octet_len); memcpy(smsp, sms->user_data, octet_len); break; case DCS_UCS2: case DCS_8BIT_DATA: smsp = msgb_put(msg, sms->user_data_len); memcpy(smsp, sms->user_data, sms->user_data_len); break; default: LOGP(DLSMS, LOGL_NOTICE, "Unhandled Data Coding Scheme: 0x%02X\n", sms->data_coding_scheme); break; } return msg->len - old_msg_len; } /* generate a msgb containing an 03.40 9.2.2.3 SMS-STATUS-REPORT TPDU derived * from struct gsm_sms, returns total size of TPDU */ static int gsm340_gen_sms_status_report_tpdu(struct msgb *msg, struct gsm_sms *sms) { uint8_t *smsp; uint8_t addr[12]; /* max len per 03.40 */ uint8_t addr_len = 0; unsigned int old_msg_len = msg->len; /* generate first octet with masked bits */ smsp = msgb_put(msg, 1); /* TP-MTI (message type indicator) */ *smsp = GSM340_SMS_STATUS_REP_SC2MS; /* TP-MMS (more messages to send), 1 = no messages */ if (0 /* FIXME */) *smsp |= (1 << 2); /* TP-SRQ (bit 5) is 0, because we support only SMS-SUBMIT and * do not support SMS-COMMAND */ /* TP-MR: Message Reference of the original SMS-SUBMIT */ smsp = msgb_put(msg, 1); *smsp = sms->msg_ref; /* TP-RA: address of the recepient of the original SMS-SUBMIT */ addr_len = gsm340_gen_addr_sub(addr, sizeof(addr), &sms->dst); smsp = msgb_put(msg, addr_len); memcpy(smsp, addr, addr_len); /* TP-SCTS: timestamp of the original SMS-SUBMIT */ smsp = msgb_put(msg, 7); gsm340_gen_scts(smsp, sms->received_time); /* TP-DT: when the original SMS-SUBMIT was delivered or failed */ smsp = msgb_put(msg, 7); gsm340_gen_scts(smsp, sms->delivered_time); /* TP-ST: Status of the original SMS-SUBMIT */ smsp = msgb_put(msg, 1); *smsp = sms->delivery_status; return msg->len - old_msg_len; } /* process an incoming TPDU (called from RP-DATA) * return value > 0: RP CAUSE for ERROR; < 0: silent error; 0 = success */ static int gsm340_rx_tpdu(struct gsm_subscriber_connection *conn, struct msgb *msg) { uint8_t *smsp = msgb_sms(msg); struct gsm_sms *gsms; unsigned int sms_alphabet; uint8_t sms_mti, sms_mms, sms_vpf, sms_rp; uint8_t *sms_vp; uint8_t da_len_bytes; uint8_t address_lv[12]; /* according to 03.40 / 9.1.2.5 */ int rc = 0; osmo_counter_inc(conn->bts->network->stats.sms.submitted); gsms = sms_alloc(); if (!gsms) return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER; /* This is a normal SMS */ gsms->type = GSM_SMS_DELIVER; /* invert those fields where 0 means active/present */ sms_mti = *smsp & 0x03; sms_mms = !!(*smsp & 0x04); sms_vpf = (*smsp & 0x18) >> 3; gsms->status_rep_req = (*smsp & 0x20); gsms->ud_hdr_ind = (*smsp & 0x40); sms_rp = (*smsp & 0x80); smsp++; gsms->msg_ref = *smsp++; /* length in bytes of the destination address */ da_len_bytes = 2 + *smsp/2 + *smsp%2; if (da_len_bytes > 12) { LOGP(DLSMS, LOGL_ERROR, "Destination Address > 12 bytes ?!?\n"); rc = GSM411_RP_CAUSE_SEMANT_INC_MSG; goto out; } else if (da_len_bytes < 4) { LOGP(DLSMS, LOGL_ERROR, "Destination Address < 4 bytes ?!?\n"); rc = GSM411_RP_CAUSE_SEMANT_INC_MSG; goto out; } memset(address_lv, 0, sizeof(address_lv)); memcpy(address_lv, smsp, da_len_bytes); /* mangle first byte to reflect length in bytes, not digits */ address_lv[0] = da_len_bytes - 1; gsms->dst.ton = (address_lv[1] >> 4) & 7; gsms->dst.npi = address_lv[1] & 0xF; /* convert to real number */ gsm48_decode_bcd_number(gsms->dst.addr, sizeof(gsms->dst.addr), address_lv, 1); smsp += da_len_bytes; gsms->protocol_id = *smsp++; gsms->data_coding_scheme = *smsp++; sms_alphabet = gsm338_get_sms_alphabet(gsms->data_coding_scheme); if (sms_alphabet == 0xffffffff) { rc = GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER; goto out; } switch (sms_vpf) { case GSM340_TP_VPF_RELATIVE: sms_vp = smsp++; break; case GSM340_TP_VPF_ABSOLUTE: case GSM340_TP_VPF_ENHANCED: sms_vp = smsp; /* the additional functionality indicator... */ if (sms_vpf == GSM340_TP_VPF_ENHANCED && *smsp & (1<<7)) smsp++; smsp += 7; break; case GSM340_TP_VPF_NONE: sms_vp = 0; break; default: LOGP(DLSMS, LOGL_NOTICE, "SMS Validity period not implemented: 0x%02x\n", sms_vpf); rc = GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER; goto out; } gsms->user_data_len = *smsp++; if (gsms->user_data_len) { memcpy(gsms->user_data, smsp, gsms->user_data_len); switch (sms_alphabet) { case DCS_7BIT_DEFAULT: gsm_7bit_decode_n(gsms->text, sizeof(gsms->text), smsp, gsms->user_data_len); break; case DCS_8BIT_DATA: case DCS_UCS2: case DCS_NONE: break; } } LOGP(DLSMS, LOGL_INFO, "RX SMS: Sender: %s, MTI: 0x%02x, VPF: 0x%02x, " "MR: 0x%02x PID: 0x%02x, DCS: 0x%02x, DA: %s, " "UserDataLength: 0x%02x, UserData: \"%s\"\n", subscr_name(conn->subscr), sms_mti, sms_vpf, gsms->msg_ref, gsms->protocol_id, gsms->data_coding_scheme, gsms->dst.addr, gsms->user_data_len, sms_alphabet == DCS_7BIT_DEFAULT ? gsms->text : osmo_hexdump(gsms->user_data, gsms->user_data_len)); gsms->received_time = time(NULL); gsms->valid_until = gsm340_validity_time(gsms->received_time, sms_vpf, sms_vp); /* FIXME: This looks very wrong */ send_signal(0, NULL, gsms, 0); /* determine gsms->receiver based on dialled number */ gsms->receiver = subscr_get_by_extension(conn->bts->network, gsms->dst.addr); if (!gsms->receiver) { #ifdef BUILD_SMPP rc = smpp_try_deliver(gsms, conn); if (rc == 1) { rc = 1; /* cause 1: unknown subscriber */ osmo_counter_inc(conn->bts->network->stats.sms.no_receiver); } else if (rc < 0) { rc = 21; /* cause 21: short message transfer rejected */ /* FIXME: handle the error somehow? */ } #else rc = 1; /* cause 1: unknown subscriber */ osmo_counter_inc(conn->bts->network->stats.sms.no_receiver); #endif goto out; } switch (sms_mti) { case GSM340_SMS_SUBMIT_MS2SC: /* MS is submitting a SMS */ rc = gsm340_rx_sms_submit(msg, gsms); break; case GSM340_SMS_COMMAND_MS2SC: case GSM340_SMS_DELIVER_REP_MS2SC: LOGP(DLSMS, LOGL_NOTICE, "Unimplemented MTI 0x%02x\n", sms_mti); rc = GSM411_RP_CAUSE_IE_NOTEXIST; break; default: LOGP(DLSMS, LOGL_NOTICE, "Undefined MTI 0x%02x\n", sms_mti); rc = GSM411_RP_CAUSE_IE_NOTEXIST; break; } if (!rc && !gsms->receiver) rc = GSM411_RP_CAUSE_MO_NUM_UNASSIGNED; out: sms_free(gsms); return rc; } /* Prefix msg with a RP-DATA header and send as SMR DATA */ static int gsm411_rp_sendmsg(struct gsm411_smr_inst *inst, struct msgb *msg, uint8_t rp_msg_type, uint8_t rp_msg_ref, int rl_msg_type) { struct gsm411_rp_hdr *rp; uint8_t len = msg->len; /* GSM 04.11 RP-DATA header */ rp = (struct gsm411_rp_hdr *)msgb_push(msg, sizeof(*rp)); rp->len = len + 2; rp->msg_type = rp_msg_type; rp->msg_ref = rp_msg_ref; return gsm411_smr_send(inst, rl_msg_type, msg); } static int gsm411_send_rp_ack(struct gsm_trans *trans, uint8_t msg_ref) { struct msgb *msg = gsm411_msgb_alloc(); DEBUGP(DLSMS, "TX: SMS RP ACK\n"); return gsm411_rp_sendmsg(&trans->sms.smr_inst, msg, GSM411_MT_RP_ACK_MT, msg_ref, GSM411_SM_RL_REPORT_REQ); } static int gsm411_send_rp_error(struct gsm_trans *trans, uint8_t msg_ref, uint8_t cause) { struct msgb *msg = gsm411_msgb_alloc(); msgb_tv_put(msg, 1, cause); LOGP(DLSMS, LOGL_NOTICE, "TX: SMS RP ERROR, cause %d (%s)\n", cause, get_value_string(gsm411_rp_cause_strs, cause)); return gsm411_rp_sendmsg(&trans->sms.smr_inst, msg, GSM411_MT_RP_ERROR_MT, msg_ref, GSM411_SM_RL_REPORT_REQ); } /* Receive a 04.11 TPDU inside RP-DATA / user data */ static int gsm411_rx_rp_ud(struct msgb *msg, struct gsm_trans *trans, struct gsm411_rp_hdr *rph, uint8_t src_len, uint8_t *src, uint8_t dst_len, uint8_t *dst, uint8_t tpdu_len, uint8_t *tpdu) { int rc = 0; if (src_len && src) LOGP(DLSMS, LOGL_ERROR, "RP-DATA (MO) with SRC ?!?\n"); if (!dst_len || !dst || !tpdu_len || !tpdu) { LOGP(DLSMS, LOGL_ERROR, "RP-DATA (MO) without DST or TPDU ?!?\n"); gsm411_send_rp_error(trans, rph->msg_ref, GSM411_RP_CAUSE_INV_MAND_INF); return -EIO; } msg->l4h = tpdu; DEBUGP(DLSMS, "DST(%u,%s)\n", dst_len, osmo_hexdump(dst, dst_len)); rc = gsm340_rx_tpdu(trans->conn, msg); if (rc == 0) return gsm411_send_rp_ack(trans, rph->msg_ref); else if (rc > 0) return gsm411_send_rp_error(trans, rph->msg_ref, rc); else return rc; } /* Receive a 04.11 RP-DATA message in accordance with Section 7.3.1.2 */ static int gsm411_rx_rp_data(struct msgb *msg, struct gsm_trans *trans, struct gsm411_rp_hdr *rph) { uint8_t src_len, dst_len, rpud_len; uint8_t *src = NULL, *dst = NULL , *rp_ud = NULL; /* in the MO case, this should always be zero length */ src_len = rph->data[0]; if (src_len) src = &rph->data[1]; dst_len = rph->data[1+src_len]; if (dst_len) dst = &rph->data[1+src_len+1]; rpud_len = rph->data[1+src_len+1+dst_len]; if (rpud_len) rp_ud = &rph->data[1+src_len+1+dst_len+1]; DEBUGP(DLSMS, "RX_RP-DATA: src_len=%u, dst_len=%u ud_len=%u\n", src_len, dst_len, rpud_len); return gsm411_rx_rp_ud(msg, trans, rph, src_len, src, dst_len, dst, rpud_len, rp_ud); } /* Receive a 04.11 RP-ACK message (response to RP-DATA from us) */ static int gsm411_rx_rp_ack(struct msgb *msg, struct gsm_trans *trans, struct gsm411_rp_hdr *rph) { struct gsm_sms *sms = trans->sms.sms; /* Acnkowledgement to MT RP_DATA, i.e. the MS confirms it * successfully received a SMS. We can now safely mark it as * transmitted */ if (!sms) { LOGP(DLSMS, LOGL_ERROR, "RX RP-ACK but no sms in transaction?!?\n"); return gsm411_send_rp_error(trans, rph->msg_ref, GSM411_RP_CAUSE_PROTOCOL_ERR); } /* mark this SMS as sent in database */ db_sms_mark_delivered(sms); send_signal(S_SMS_DELIVERED, trans, sms, 0); LOGP(DLSMS, LOGL_ERROR, "Checking for status report: %d\n", sms->status_rep_req); if (sms->status_rep_req) { LOGP(DLSMS, LOGL_ERROR, "Going to send report\n"); send_status_rep(trans->subscr->net, sms); } sms_free(sms); trans->sms.sms = NULL; return 0; } static int gsm411_rx_rp_error(struct msgb *msg, struct gsm_trans *trans, struct gsm411_rp_hdr *rph) { struct gsm_network *net = trans->conn->bts->network; struct gsm_sms *sms = trans->sms.sms; uint8_t cause_len = rph->data[0]; uint8_t cause = rph->data[1]; /* Error in response to MT RP_DATA, i.e. the MS did not * successfully receive the SMS. We need to investigate * the cause and take action depending on it */ LOGP(DLSMS, LOGL_NOTICE, "%s: RX SMS RP-ERROR, cause %d:%d (%s)\n", subscr_name(trans->conn->subscr), cause_len, cause, get_value_string(gsm411_rp_cause_strs, cause)); if (!sms) { LOGP(DLSMS, LOGL_ERROR, "RX RP-ERR, but no sms in transaction?!?\n"); return -EINVAL; #if 0 return gsm411_send_rp_error(trans, rph->msg_ref, GSM411_RP_CAUSE_PROTOCOL_ERR); #endif } if (cause == GSM411_RP_CAUSE_MT_MEM_EXCEEDED) { /* MS has not enough memory to store the message. We need * to store this in our database and wait for a SMMA message */ /* FIXME */ send_signal(S_SMS_MEM_EXCEEDED, trans, sms, 0); osmo_counter_inc(net->stats.sms.rp_err_mem); } else { send_signal(S_SMS_UNKNOWN_ERROR, trans, sms, 0); osmo_counter_inc(net->stats.sms.rp_err_other); } sms_free(sms); trans->sms.sms = NULL; return 0; } static int gsm411_rx_rp_smma(struct msgb *msg, struct gsm_trans *trans, struct gsm411_rp_hdr *rph) { int rc; rc = gsm411_send_rp_ack(trans, rph->msg_ref); /* MS tells us that it has memory for more SMS, we need * to check if we have any pending messages for it and then * transfer those */ send_signal(S_SMS_SMMA, trans, NULL, 0); return rc; } /* receive RL DATA */ static int gsm411_rx_rl_data(struct msgb *msg, struct gsm48_hdr *gh, struct gsm_trans *trans) { struct gsm411_rp_hdr *rp_data = (struct gsm411_rp_hdr*)&gh->data; uint8_t msg_type = rp_data->msg_type & 0x07; int rc = 0; switch (msg_type) { case GSM411_MT_RP_DATA_MO: DEBUGP(DLSMS, "RX SMS RP-DATA (MO)\n"); rc = gsm411_rx_rp_data(msg, trans, rp_data); break; case GSM411_MT_RP_SMMA_MO: DEBUGP(DLSMS, "RX SMS RP-SMMA\n"); rc = gsm411_rx_rp_smma(msg, trans, rp_data); break; default: LOGP(DLSMS, LOGL_NOTICE, "Invalid RP type 0x%02x\n", msg_type); rc = -EINVAL; break; } return rc; } /* receive RL REPORT */ static int gsm411_rx_rl_report(struct msgb *msg, struct gsm48_hdr *gh, struct gsm_trans *trans) { struct gsm411_rp_hdr *rp_data = (struct gsm411_rp_hdr*)&gh->data; uint8_t msg_type = rp_data->msg_type & 0x07; int rc = 0; switch (msg_type) { case GSM411_MT_RP_ACK_MO: DEBUGP(DLSMS, "RX SMS RP-ACK (MO)\n"); rc = gsm411_rx_rp_ack(msg, trans, rp_data); break; case GSM411_MT_RP_ERROR_MO: DEBUGP(DLSMS, "RX SMS RP-ERROR (MO)\n"); rc = gsm411_rx_rp_error(msg, trans, rp_data); break; default: LOGP(DLSMS, LOGL_NOTICE, "Invalid RP type 0x%02x\n", msg_type); rc = -EINVAL; break; } return rc; } /* receive SM-RL sap message from SMR * NOTE: Message is freed by sender */ int gsm411_rl_recv(struct gsm411_smr_inst *inst, int msg_type, struct msgb *msg) { struct gsm_trans *trans = container_of(inst, struct gsm_trans, sms.smr_inst); struct gsm48_hdr *gh = msgb_l3(msg); int rc = 0; switch (msg_type) { case GSM411_SM_RL_DATA_IND: rc = gsm411_rx_rl_data(msg, gh, trans); break; case GSM411_SM_RL_REPORT_IND: if (gh) rc = gsm411_rx_rl_report(msg, gh, trans); break; default: LOGP(DLSMS, LOGL_NOTICE, "Unhandled SM-RL message 0x%x\n", msg_type); rc = -EINVAL; } return rc; } /* receive MNCCSMS sap message from SMC * NOTE: Message is freed by sender */ static int gsm411_mn_recv(struct gsm411_smc_inst *inst, int msg_type, struct msgb *msg) { struct gsm_trans *trans = container_of(inst, struct gsm_trans, sms.smc_inst); struct gsm48_hdr *gh = msgb_l3(msg); int rc = 0; switch (msg_type) { case GSM411_MNSMS_EST_IND: case GSM411_MNSMS_DATA_IND: DEBUGP(DLSMS, "MNSMS-DATA/EST-IND\n"); rc = gsm411_smr_recv(&trans->sms.smr_inst, msg_type, msg); break; case GSM411_MNSMS_ERROR_IND: if (gh) DEBUGP(DLSMS, "MNSMS-ERROR-IND, cause %d (%s)\n", gh->data[0], get_value_string(gsm411_cp_cause_strs, gh->data[0])); else DEBUGP(DLSMS, "MNSMS-ERROR-IND, no cause\n"); rc = gsm411_smr_recv(&trans->sms.smr_inst, msg_type, msg); break; default: LOGP(DLSMS, LOGL_NOTICE, "Unhandled MNCCSMS msg 0x%x\n", msg_type); rc = -EINVAL; } return rc; } /* Entry point for incoming GSM48_PDISC_SMS from abis_rsl.c */ int gsm0411_rcv_sms(struct gsm_subscriber_connection *conn, struct msgb *msg) { struct gsm48_hdr *gh = msgb_l3(msg); uint8_t msg_type = gh->msg_type; uint8_t transaction_id = ((gh->proto_discr >> 4) ^ 0x8); /* flip */ struct gsm_trans *trans; int new_trans = 0; int rc = 0; if (!conn->subscr) return -EIO; /* FIXME: send some error message */ DEBUGP(DLSMS, "receiving data (trans_id=%x)\n", transaction_id); trans = trans_find_by_id(conn->subscr, GSM48_PDISC_SMS, transaction_id); /* * A transaction we created but don't know about? */ if (!trans && (transaction_id & 0x8) == 0) { LOGP(DLSMS, LOGL_ERROR, "trans_id=%x allocated by us but known " "to us anymore. We are ignoring it, maybe a CP-ERROR " "from a MS?\n", transaction_id); return -EINVAL; } if (!trans) { DEBUGP(DLSMS, " -> (new transaction)\n"); trans = trans_alloc(conn->subscr, GSM48_PDISC_SMS, transaction_id, new_callref++); if (!trans) { DEBUGP(DLSMS, " -> No memory for trans\n"); /* FIXME: send some error message */ return -ENOMEM; } gsm411_smc_init(&trans->sms.smc_inst, 0, 1, gsm411_mn_recv, gsm411_mm_send); gsm411_smr_init(&trans->sms.smr_inst, 0, 1, gsm411_rl_recv, gsm411_mn_send); trans->conn = conn; new_trans = 1; } /* 5.4: For MO, if a CP-DATA is received for a new * transaction, equals reception of an implicit * last CP-ACK for previous transaction */ if (trans->sms.smc_inst.cp_state == GSM411_CPS_IDLE && msg_type == GSM411_MT_CP_DATA) { int i; struct gsm_trans *ptrans; /* Scan through all remote initiated transactions */ for (i=8; i<15; i++) { if (i == transaction_id) continue; ptrans = trans_find_by_id(conn->subscr, GSM48_PDISC_SMS, i); if (!ptrans) continue; DEBUGP(DLSMS, "Implicit CP-ACK for trans_id=%x\n", i); /* Finish it for good */ trans_free(ptrans); } } gsm411_smc_recv(&trans->sms.smc_inst, (new_trans) ? GSM411_MMSMS_EST_IND : GSM411_MMSMS_DATA_IND, msg, msg_type); return rc; } /* Take a SMS in gsm_sms structure and send it through an already * existing lchan. We also assume that the caller ensured this lchan already * has a SAPI3 RLL connection! */ int gsm411_send_sms(struct gsm_subscriber_connection *conn, struct gsm_sms *sms) { struct msgb *msg = gsm411_msgb_alloc(); struct gsm_trans *trans; uint8_t *data, *rp_ud_len; uint8_t msg_ref = sms_next_rp_msg_ref(conn); int transaction_id; int rc; transaction_id = trans_assign_trans_id(conn->subscr, GSM48_PDISC_SMS, 0); if (transaction_id == -1) { LOGP(DLSMS, LOGL_ERROR, "No available transaction ids\n"); send_signal(S_SMS_UNKNOWN_ERROR, NULL, sms, 0); sms_free(sms); return -EBUSY; } DEBUGP(DLSMS, "send_sms_lchan()\n"); /* FIXME: allocate transaction with message reference */ trans = trans_alloc(conn->subscr, GSM48_PDISC_SMS, transaction_id, new_callref++); if (!trans) { LOGP(DLSMS, LOGL_ERROR, "No memory for trans\n"); send_signal(S_SMS_UNKNOWN_ERROR, NULL, sms, 0); sms_free(sms); /* FIXME: send some error message */ return -ENOMEM; } gsm411_smc_init(&trans->sms.smc_inst, sms->id, 1, gsm411_mn_recv, gsm411_mm_send); gsm411_smr_init(&trans->sms.smr_inst, sms->id, 1, gsm411_rl_recv, gsm411_mn_send); trans->sms.sms = sms; trans->conn = conn; /* Hardcode SMSC Originating Address for now */ data = (uint8_t *)msgb_put(msg, 8); data[0] = 0x07; /* originator length == 7 */ data[1] = 0x91; /* type of number: international, ISDN */ data[2] = 0x44; /* 447785016005 */ data[3] = 0x77; data[4] = 0x58; data[5] = 0x10; data[6] = 0x06; data[7] = 0x50; /* Hardcoded Destination Address */ data = (uint8_t *)msgb_put(msg, 1); data[0] = 0; /* destination length == 0 */ /* obtain a pointer for the rp_ud_len, so we can fill it later */ rp_ud_len = (uint8_t *)msgb_put(msg, 1); switch (sms->type) { case GSM_SMS_DELIVER: /* generate the 03.40 SMS-DELIVER TPDU */ LOGP(DLSMS, LOGL_ERROR, "Calling gsm340_gen_sms_deliver_tpdu()\n"); rc = gsm340_gen_sms_deliver_tpdu(msg, sms); break; case GSM_SMS_STATUS_REP: /* generate the 03.40 SMS-STATUS-REP TPDU */ /* TODO: proper time and status */ LOGP(DLSMS, LOGL_ERROR, "Calling gsm340_gen_sms_status_report_tpdu()\n"); rc = gsm340_gen_sms_status_report_tpdu(msg, sms); break; default: LOGP(DLSMS, LOGL_ERROR, "Unkown SMS type when generating TPDU\n"); rc = -1; } if (rc < 0) { send_signal(S_SMS_UNKNOWN_ERROR, trans, sms, 0); sms_free(sms); trans->sms.sms = NULL; trans_free(trans); msgb_free(msg); return rc; } *rp_ud_len = rc; DEBUGP(DLSMS, "TX: SMS DELIVER\n"); osmo_counter_inc(conn->bts->network->stats.sms.delivered); db_sms_inc_deliver_attempts(trans->sms.sms); return gsm411_rp_sendmsg(&trans->sms.smr_inst, msg, GSM411_MT_RP_DATA_MT, msg_ref, GSM411_SM_RL_DATA_REQ); } /* paging callback. Here we get called if paging a subscriber has * succeeded or failed. */ static int paging_cb_send_sms(unsigned int hooknum, unsigned int event, struct msgb *msg, void *_conn, void *_sms) { struct gsm_subscriber_connection *conn = _conn; struct gsm_sms *sms = _sms; int rc = 0; DEBUGP(DLSMS, "paging_cb_send_sms(hooknum=%u, event=%u, msg=%p," "conn=%p, sms=%p/id: %llu)\n", hooknum, event, msg, conn, sms, sms->id); if (hooknum != GSM_HOOK_RR_PAGING) return -EINVAL; switch (event) { case GSM_PAGING_SUCCEEDED: gsm411_send_sms(conn, sms); break; case GSM_PAGING_EXPIRED: case GSM_PAGING_OOM: case GSM_PAGING_BUSY: send_signal(S_SMS_UNKNOWN_ERROR, NULL, sms, event); sms_free(sms); rc = -ETIMEDOUT; break; default: LOGP(DLSMS, LOGL_ERROR, "Unhandled paging event: %d\n", event); } return rc; } /* high-level function to send a SMS to a given subscriber. The function * will take care of paging the subscriber, establishing the RLL SAPI3 * connection, etc. */ int gsm411_send_sms_subscr(struct gsm_subscriber *subscr, struct gsm_sms *sms) { struct gsm_subscriber_connection *conn; /* check if we already have an open lchan to the subscriber. * if yes, send the SMS this way */ conn = connection_for_subscr(subscr); if (conn) { return gsm411_send_sms(conn, sms); } /* if not, we have to start paging */ subscr_get_channel(subscr, RSL_CHANNEED_SDCCH, paging_cb_send_sms, sms); return 0; } void _gsm411_sms_trans_free(struct gsm_trans *trans) { /* cleanup SMS instance */ gsm411_smr_clear(&trans->sms.smr_inst); trans->sms.smr_inst.rl_recv = NULL; trans->sms.smr_inst.mn_send = NULL; gsm411_smc_clear(&trans->sms.smc_inst); trans->sms.smc_inst.mn_recv = NULL; trans->sms.smc_inst.mm_send = NULL; if (trans->sms.sms) { LOGP(DLSMS, LOGL_ERROR, "Transaction contains SMS.\n"); send_signal(S_SMS_UNKNOWN_ERROR, trans, trans->sms.sms, 0); sms_free(trans->sms.sms); trans->sms.sms = NULL; } } void gsm411_sapi_n_reject(struct gsm_subscriber_connection *conn) { struct gsm_network *net; struct gsm_trans *trans, *tmp; net = conn->bts->network; llist_for_each_entry_safe(trans, tmp, &net->trans_list, entry) { struct gsm_sms *sms; if (trans->conn != conn) continue; if (trans->protocol != GSM48_PDISC_SMS) continue; sms = trans->sms.sms; if (!sms) { LOGP(DLSMS, LOGL_ERROR, "SAPI Reject but no SMS.\n"); continue; } send_signal(S_SMS_UNKNOWN_ERROR, trans, sms, 0); sms_free(sms); trans->sms.sms = NULL; trans_free(trans); } }