diff options
Diffstat (limited to 'src/libmsc')
-rw-r--r-- | src/libmsc/gsm_04_11.c | 351 | ||||
-rw-r--r-- | src/libmsc/msc_vty.c | 4 | ||||
-rw-r--r-- | src/libmsc/smpp_openbsc.c | 2 | ||||
-rw-r--r-- | src/libmsc/sms_queue.c | 14 |
4 files changed, 204 insertions, 167 deletions
diff --git a/src/libmsc/gsm_04_11.c b/src/libmsc/gsm_04_11.c index 14f9f57e5..88dc43337 100644 --- a/src/libmsc/gsm_04_11.c +++ b/src/libmsc/gsm_04_11.c @@ -127,6 +127,87 @@ static int gsm411_sendmsg(struct gsm_subscriber_connection *conn, struct msgb *m return msc_tx_dtap(conn, msg); } +/* Paging callback for MT SMS (Paging is triggered by SMC) */ +static int paging_cb_mmsms_est_req(unsigned int hooknum, unsigned int event, + struct msgb *msg, void *_conn, void *_trans) +{ + struct gsm_subscriber_connection *conn = _conn; + struct gsm_trans *trans = _trans; + struct gsm_sms *sms = trans->sms.sms; + int rc = 0; + + DEBUGP(DLSMS, "paging_cb_mmsms_est_req(hooknum=%u, event=%u, " + "conn=%p, trans=%p)\n", hooknum, event, conn, trans); + + if (hooknum != GSM_HOOK_RR_PAGING) + return -EINVAL; + + /* Paging procedure has finished */ + trans->paging_request = NULL; + + switch (event) { + case GSM_PAGING_SUCCEEDED: + /* Associate transaction with established connection */ + trans->conn = msc_subscr_conn_get(conn, MSC_CONN_USE_TRANS_SMS); + /* FIXME: specify SACCH in case we already have active TCH */ + trans->dlci = 0x03; + /* Confirm successful connection establishment */ + gsm411_smc_recv(&trans->sms.smc_inst, + GSM411_MMSMS_EST_CNF, NULL, 0); + break; + case GSM_PAGING_EXPIRED: + case GSM_PAGING_BUSY: + /* Inform SMC about channel establishment failure */ + gsm411_smc_recv(&trans->sms.smc_inst, + GSM411_MMSMS_REL_IND, NULL, 0); + + /* Notify the SMSqueue and free stored SMS */ + send_signal(S_SMS_UNKNOWN_ERROR, NULL, sms, event); + trans->sms.sms = NULL; + sms_free(sms); + + /* Destroy this transaction */ + trans_free(trans); + rc = -ETIMEDOUT; + break; + default: + LOGP(DLSMS, LOGL_ERROR, "Unhandled paging event: %d\n", event); + } + + return rc; +} + +static int gsm411_mmsms_est_req(struct gsm_trans *trans) +{ + /* Subscriber's data shall be associated */ + OSMO_ASSERT(trans->vsub != NULL); + + /* Check if connection is already established */ + if (trans->conn != NULL) { + LOGP(DLSMS, LOGL_DEBUG, "Using an existing connection " + "for %s\n", vlr_subscr_name(trans->vsub)); + return gsm411_smc_recv(&trans->sms.smc_inst, + GSM411_MMSMS_EST_CNF, NULL, 0); + } + + /* Initiate Paging procedure */ + LOGP(DLSMS, LOGL_DEBUG, "Initiating Paging procedure " + "for %s due to MMSMS_EST_REQ\n", vlr_subscr_name(trans->vsub)); + trans->paging_request = subscr_request_conn(trans->vsub, + paging_cb_mmsms_est_req, trans, "MT SMS"); + if (!trans->paging_request) { + LOGP(DLSMS, LOGL_ERROR, "Failed to initiate Paging " + "procedure for %s\n", vlr_subscr_name(trans->vsub)); + /* Inform SMC about channel establishment failure */ + gsm411_smc_recv(&trans->sms.smc_inst, + GSM411_MMSMS_REL_IND, NULL, 0); + trans_free(trans); + return -EIO; + } + + return 0; +} + /* 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) @@ -154,8 +235,7 @@ static int gsm411_mm_send(struct gsm411_smc_inst *inst, int msg_type, switch (msg_type) { case GSM411_MMSMS_EST_REQ: - /* recycle msg */ - rc = gsm411_smc_recv(inst, GSM411_MMSMS_EST_CNF, msg, 0); + rc = gsm411_mmsms_est_req(trans); msgb_free(msg); /* upper layer does not free msg */ break; case GSM411_MMSMS_DATA_REQ: @@ -899,6 +979,120 @@ static int gsm411_mn_recv(struct gsm411_smc_inst *inst, int msg_type, return rc; } +static struct gsm_trans *gsm411_alloc_mt_trans(struct gsm_network *net, + struct vlr_subscr *vsub) +{ + struct gsm_subscriber_connection *conn; + struct gsm_trans *trans; + int tid; + + LOGP(DLSMS, LOGL_INFO, "Going to send a MT SMS\n"); + + /* Generate a new transaction ID */ + tid = trans_assign_trans_id(net, vsub, GSM48_PDISC_SMS, 0); + if (tid == -1) { + LOGP(DLSMS, LOGL_ERROR, "No available transaction IDs\n"); + return NULL; + } + + /* Allocate a new transaction */ + trans = trans_alloc(net, vsub, GSM48_PDISC_SMS, tid, new_callref++); + if (!trans) { + LOGP(DLSMS, LOGL_ERROR, "No memory for trans\n"); + return NULL; + } + + /* Init both SMC and SMR state machines */ + 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); + + /* Attempt to find an existing connection */ + conn = connection_for_subscr(vsub); + if (conn) { + /* Associate transaction with connection */ + trans->conn = msc_subscr_conn_get(conn, MSC_CONN_USE_TRANS_SMS); + /* Generate unique RP Message Reference */ + trans->sms.sm_rp_mr = conn->next_rp_ref++; + } + + return trans; +} + +/* High-level function to send an SMS to a given subscriber */ +int gsm411_send_sms(struct gsm_network *net, + struct vlr_subscr *vsub, + struct gsm_sms *sms) +{ + uint8_t *data, *rp_ud_len; + struct gsm_trans *trans; + struct msgb *msg; + int rc; + + /* Allocate a new transaction for MT SMS */ + trans = gsm411_alloc_mt_trans(net, vsub); + if (!trans) { + send_signal(S_SMS_UNKNOWN_ERROR, NULL, sms, 0); + sms_free(sms); + return -ENOMEM; + } + + /* Allocate a message buffer for to be encoded SMS */ + msg = gsm411_msgb_alloc(); + if (!msg) { + send_signal(S_SMS_UNKNOWN_ERROR, NULL, sms, 0); + trans_free(trans); + sms_free(sms); + return -ENOMEM; + } + + /* 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); + + if (sms->is_report) { + /* generate the 03.40 SMS-STATUS-REPORT TPDU */ + rc = gsm340_gen_sms_status_report_tpdu(msg, sms); + } else { + /* generate the 03.40 SMS-DELIVER TPDU */ + rc = gsm340_gen_sms_deliver_tpdu(msg, sms); + } + if (rc < 0) { + send_signal(S_SMS_UNKNOWN_ERROR, trans, sms, 0); + sms_free(sms); + trans_free(trans); + msgb_free(msg); + return rc; + } + + *rp_ud_len = rc; + + /* Store a pointer to abstract SMS representation */ + trans->sms.sms = sms; + + rate_ctr_inc(&net->msc_ctrs->ctr[MSC_CTR_SMS_DELIVERED]); + db_sms_inc_deliver_attempts(trans->sms.sms); + + return gsm411_rp_sendmsg(&trans->sms.smr_inst, msg, + GSM411_MT_RP_DATA_MT, trans->sms.sm_rp_mr, + GSM411_SM_RL_DATA_REQ); +} + /* Entry point for incoming GSM48_PDISC_SMS from abis_rsl.c */ int gsm0411_rcv_sms(struct gsm_subscriber_connection *conn, struct msgb *msg) @@ -985,159 +1179,6 @@ int gsm0411_rcv_sms(struct gsm_subscriber_connection *conn, return rc; } -/* Take a SMS in gsm_sms structure and send it through an already - * existing conn. We also assume that the caller ensured this conn 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 = conn->next_rp_ref++; - int transaction_id; - int rc; - - transaction_id = - trans_assign_trans_id(conn->network, conn->vsub, - 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); - msgb_free(msg); - return -EBUSY; - } - - DEBUGP(DLSMS, "%s()\n", __func__); - - /* FIXME: allocate transaction with message reference */ - trans = trans_alloc(conn->network, conn->vsub, - 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); - msgb_free(msg); - /* 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 = msc_subscr_conn_get(conn, MSC_CONN_USE_TRANS_SMS); - trans->dlci = 0x03; - /* FIXME: specify SACCH in case we already have active TCH */ - - /* 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); - - if (sms->is_report) { - /* generate the 03.40 SMS-STATUS-REPORT TPDU */ - rc = gsm340_gen_sms_status_report_tpdu(msg, sms); - } else { - /* generate the 03.40 SMS-DELIVER TPDU */ - rc = gsm340_gen_sms_deliver_tpdu(msg, sms); - } - 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"); - - rate_ctr_inc(&conn->network->msc_ctrs->ctr[MSC_CTR_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_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 vlr_subscr *vsub, - struct gsm_sms *sms) -{ - struct gsm_subscriber_connection *conn; - void *res; - - /* check if we already have an open conn to the subscriber. - * if yes, send the SMS this way */ - conn = connection_for_subscr(vsub); - if (conn) { - LOGP(DLSMS, LOGL_DEBUG, "Sending SMS via already open connection %p to %s\n", - conn, vlr_subscr_name(vsub)); - return gsm411_send_sms(conn, sms); - } - - /* if not, we have to start paging */ - LOGP(DLSMS, LOGL_DEBUG, "Sending SMS: no connection open, start paging %s\n", - vlr_subscr_name(vsub)); - res = subscr_request_conn(vsub, paging_cb_send_sms, sms, "send SMS"); - if (!res) { - send_signal(S_SMS_UNKNOWN_ERROR, NULL, sms, GSM_PAGING_BUSY); - sms_free(sms); - } - return 0; -} - void _gsm411_sms_trans_free(struct gsm_trans *trans) { /* cleanup SMS instance */ diff --git a/src/libmsc/msc_vty.c b/src/libmsc/msc_vty.c index cdf31842b..4f3ac04c7 100644 --- a/src/libmsc/msc_vty.c +++ b/src/libmsc/msc_vty.c @@ -680,7 +680,7 @@ DEFUN(sms_send_pend, break; if (sms->receiver) - gsm411_send_sms_subscr(sms->receiver, sms); + gsm411_send_sms(gsmnet, sms->receiver, sms); sms_id = sms->id + 1; } @@ -819,7 +819,7 @@ DEFUN(subscriber_send_pending_sms, sms = db_sms_get_unsent_for_subscr(vsub, UINT_MAX); if (sms) - gsm411_send_sms_subscr(sms->receiver, sms); + gsm411_send_sms(gsmnet, sms->receiver, sms); vlr_subscr_put(vsub); diff --git a/src/libmsc/smpp_openbsc.c b/src/libmsc/smpp_openbsc.c index c12db5f3e..051372c08 100644 --- a/src/libmsc/smpp_openbsc.c +++ b/src/libmsc/smpp_openbsc.c @@ -268,7 +268,7 @@ int handle_smpp_submit(struct osmo_esme *esme, struct submit_sm_t *submit, LOGP(DLSMS, LOGL_DEBUG, "SMPP SUBMIT-SM: Forwarding in " "real time (Transaction/Forward mode)\n"); sms->smpp.transaction_mode = 1; - gsm411_send_sms_subscr(sms->receiver, sms); + gsm411_send_sms(net, sms->receiver, sms); rc = 1; /* don't send any response yet */ break; } diff --git a/src/libmsc/sms_queue.c b/src/libmsc/sms_queue.c index 252e52986..9907f4f94 100644 --- a/src/libmsc/sms_queue.c +++ b/src/libmsc/sms_queue.c @@ -186,7 +186,7 @@ static void sms_resend_pending(void *_data) sms_queue_trigger(smsq); } else { pending->resend = 0; - gsm411_send_sms_subscr(sms->receiver, sms); + gsm411_send_sms(smsq->network, sms->receiver, sms); } } } @@ -311,7 +311,7 @@ static void sms_submit_pending(void *_data) attempted += 1; smsq->pending += 1; llist_add_tail(&pending->entry, &smsq->pending_sms); - gsm411_send_sms_subscr(sms->receiver, sms); + gsm411_send_sms(smsq->network, sms->receiver, sms); } while (attempted < attempts && rounds < 1000); LOGP(DLSMS, LOGL_DEBUG, "SMSqueue added %d messages in %d rounds\n", attempted, rounds); @@ -349,7 +349,7 @@ static void sms_send_next(struct vlr_subscr *vsub) smsq->pending += 1; llist_add_tail(&pending->entry, &smsq->pending_sms); - gsm411_send_sms_subscr(sms->receiver, sms); + gsm411_send_sms(smsq->network, sms->receiver, sms); return; no_pending_sms: @@ -398,7 +398,6 @@ static int sub_ready_for_sm(struct gsm_network *net, struct vlr_subscr *vsub) { struct gsm_sms *sms; struct gsm_sms_pending *pending; - struct gsm_subscriber_connection *conn; /* * The code used to be very clever and tried to submit @@ -423,15 +422,12 @@ static int sub_ready_for_sm(struct gsm_network *net, struct vlr_subscr *vsub) return 0; } - conn = connection_for_subscr(vsub); - if (!conn) - return -1; - /* Now try to deliver any pending SMS to this sub */ sms = db_sms_get_unsent_for_subscr(vsub, UINT_MAX); if (!sms) return -1; - gsm411_send_sms(conn, sms); + + gsm411_send_sms(net, vsub, sms); return 0; } |