blob: 32dac61b3f886c44b0d11b383a215f29b89f764f [file] [log] [blame]
Harald Welte2dba82d2012-11-08 16:14:37 +01001/* OpenBSC SMPP 3.4 interface, SMSC-side implementation */
2
3/* (C) 2012 by Harald Welte <laforge@gnumonks.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20
21#include <stdio.h>
22#include <unistd.h>
23#include <string.h>
24#include <stdint.h>
25#include <errno.h>
26
27#include <smpp34.h>
28#include <smpp34_structs.h>
29#include <smpp34_params.h>
30
31#include <osmocom/core/utils.h>
32#include <osmocom/core/msgb.h>
33#include <osmocom/core/logging.h>
34#include <osmocom/core/talloc.h>
35#include <osmocom/gsm/protocol/gsm_04_11.h>
36
37#include <openbsc/gsm_subscriber.h>
38#include <openbsc/debug.h>
39#include <openbsc/db.h>
40#include <openbsc/gsm_04_11.h>
Harald Welte43413092012-11-08 19:44:08 +010041#include <openbsc/gsm_data.h>
42#include <openbsc/signal.h>
Harald Welte2dba82d2012-11-08 16:14:37 +010043
44#include "smpp_smsc.h"
45
46
47static struct gsm_subscriber *subscr_by_dst(struct gsm_network *net,
48 uint8_t npi, uint8_t ton, const char *addr)
49{
50 struct gsm_subscriber *subscr = NULL;
51
52 switch (npi) {
53 case NPI_Land_Mobile_E212:
54 subscr = subscr_get_by_imsi(net, addr);
55 break;
56 case NPI_ISDN_E163_E164:
57 case NPI_Private:
58 subscr = subscr_get_by_extension(net, addr);
59 break;
60 default:
61 LOGP(DSMPP, LOGL_NOTICE, "Unsupported NPI: %u\n", npi);
62 break;
63 }
64
65 return subscr;
66}
67
68struct tlv_t *find_tlv(struct tlv_t *head, uint16_t tag)
69{
70 struct tlv_t *t;
71
72 for (t = head; t != NULL; t = t->next) {
73 if (t->tag == tag)
74 return t;
75 }
76 return NULL;
77}
78
79/* convert from submit_sm_t to gsm_sms */
80static int submit_to_sms(struct gsm_sms **psms, struct gsm_network *net,
81 const struct submit_sm_t *submit)
82{
83 struct gsm_subscriber *dest;
84 struct gsm_sms *sms;
85 struct tlv_t *t;
86 const uint8_t *sms_msg;
87 unsigned int sms_msg_len;
88
89 dest = subscr_by_dst(net, submit->dest_addr_npi,
90 submit->dest_addr_ton,
91 (const char *)submit->destination_addr);
92 if (!dest) {
93 LOGP(DSMS, LOGL_NOTICE, "SMPP SUBMIT-SM for unknown subscriber: "
94 "%s (NPI=%u)\n", submit->destination_addr,
95 submit->dest_addr_npi);
96 return ESME_RINVDSTADR;
97 }
98
99 t = find_tlv(submit->tlv, TLVID_message_payload);
100 if (t) {
101 if (submit->sm_length) {
102 /* ERROR: we cannot have botH! */
103 return ESME_ROPTPARNOTALLWD;
104 }
105 sms_msg = t->value.octet;
106 sms_msg_len = t->length;
107 } else if (submit->short_message && submit->sm_length) {
108 sms_msg = submit->short_message;
109 sms_msg_len = submit->sm_length;
110 } else {
111 sms_msg = NULL;
112 sms_msg_len = 0;
113 }
114
115 sms = sms_alloc();
Harald Welte43413092012-11-08 19:44:08 +0100116 sms->source = SMS_SOURCE_SMPP;
117 sms->smpp.sequence_nr = submit->sequence_number;
Harald Welte2dba82d2012-11-08 16:14:37 +0100118 sms->receiver = subscr_get(dest);
119 strncpy(sms->dest_addr, dest->extension, sizeof(sms->dest_addr)-1);
120 sms->sender = subscr_get_by_id(net, 1);
121
122 if (submit->esm_class & 0x40)
123 sms->ud_hdr_ind = 1;
124
125 if (submit->esm_class & 0x80) {
126 sms->reply_path_req = 1;
127#warning Implement reply path
128 }
129
130 switch (submit->data_coding) {
131 case 0x00:
132 case 0x01: /* GSM default alphabet */
133 sms->data_coding_scheme = GSM338_DCS_1111_7BIT;
134 strncpy(sms->text, (char *)sms_msg,
135 OSMO_MIN(sizeof(sms->text)-1, sms_msg_len));
136 sms->user_data_len = gsm_7bit_encode(sms->user_data, sms->text);
137 break;
138 case 0x02:
139 case 0x04: /* 8-bit binary */
140 sms->data_coding_scheme = GSM338_DCS_1111_8BIT_DATA;
141 memcpy(sms->user_data, sms_msg, sms_msg_len);
142 sms->user_data_len = sms_msg_len;
143 break;
144 case 0x80: /* UCS-2 */
145 sms->data_coding_scheme = (2 << 2);
146 memcpy(sms->user_data, sms_msg, submit->sm_length);
147 sms->user_data_len = sms_msg_len;
148 break;
149 /* FIXME */
150 default:
151 sms_free(sms);
152 return ESME_RUNKNOWNERR;
153 }
154
155 *psms = sms;
156 return ESME_ROK;
157}
158
159int handle_smpp_submit(struct osmo_esme *esme, struct submit_sm_t *submit,
160 struct submit_sm_resp_t *submit_r)
161{
162 struct gsm_sms *sms;
163 int rc = -1;
164
165 rc = submit_to_sms(&sms, esme->smsc->priv, submit);
166 if (rc != ESME_ROK) {
167 submit_r->command_status = rc;
168 return 0;
169 }
Harald Welte43413092012-11-08 19:44:08 +0100170 sms->smpp.esme = esme;
Harald Welte2dba82d2012-11-08 16:14:37 +0100171 /* FIXME: TP-PID */
172
173 switch (submit->esm_class & 3) {
174 case 0: /* default */
175 case 1: /* datagram */
176 case 3: /* store-and-forward */
177 rc = db_sms_store(sms);
178 if (rc < 0) {
179 LOGP(DSMS, LOGL_ERROR, "SMPP SUBMIT-SM: Unable to "
180 "store SMS in database\n");
181 sms_free(sms);
182 submit_r->command_status = ESME_RSYSERR;
183 return 0;
184 }
185 strcpy((char *)submit_r->message_id, "msg_id_not_implemented");
186 LOGP(DSMS, LOGL_INFO, "SMPP SUBMIT-SM: Stored in DB\n");
187 rc = 0;
188 break;
189 case 2: /* forward (i.e. transaction) mode */
Harald Welte43413092012-11-08 19:44:08 +0100190 sms->smpp.transaction_mode = 1;
191 gsm411_send_sms_subscr(sms->receiver, sms);
Harald Welte2dba82d2012-11-08 16:14:37 +0100192 rc = 1; /* don't send any response yet */
193 break;
194 }
195 return rc;
196}
197
Harald Welte43413092012-11-08 19:44:08 +0100198static int smpp_sms_cb(unsigned int subsys, unsigned int signal,
199 void *handler_data, void *signal_data)
200{
201 struct gsm_network *network = handler_data;
202 struct sms_signal_data *sig_sms = signal_data;
203 struct gsm_sms *sms = sig_sms->sms;
204 int rc = 0;
205
206 if (!sms)
207 return 0;
208
209 if (sms->source != SMS_SOURCE_SMPP)
210 return 0;
211
212 switch (signal) {
213 case S_SMS_UNKNOWN_ERROR:
214 if (sms->smpp.transaction_mode) {
215 /* Send back the SUBMIT-SM response with apropriate error */
216 LOGP(DSMS, LOGL_INFO, "SMPP SUBMIT-SM: Error\n");
217 rc = smpp_tx_submit_r(sms->smpp.esme,
218 sms->smpp.sequence_nr,
219 ESME_RDELIVERYFAILURE,
220 sms->smpp.msg_id);
221 }
222 break;
223 case S_SMS_DELIVERED:
224 /* SMS layer tells us the delivery has been completed */
225 if (sms->smpp.transaction_mode) {
226 /* Send back the SUBMIT-SM response */
227 LOGP(DSMS, LOGL_INFO, "SMPP SUBMIT-SM: Success\n");
228 rc = smpp_tx_submit_r(sms->smpp.esme,
229 sms->smpp.sequence_nr,
230 ESME_ROK, sms->smpp.msg_id);
231 }
232 break;
233 }
234
235 return rc;
236}
237
Harald Welte2dba82d2012-11-08 16:14:37 +0100238
239int smpp_openbsc_init(struct gsm_network *net, uint16_t port)
240{
241 struct smsc *smsc = talloc_zero(net, struct smsc);
242 int rc;
243
244 smsc->priv = net;
245
246 rc = smpp_smsc_init(smsc, port);
247 if (rc < 0)
248 talloc_free(smsc);
249
Harald Welte43413092012-11-08 19:44:08 +0100250 osmo_signal_register_handler(SS_SMS, smpp_sms_cb, net);
251
Harald Welte2dba82d2012-11-08 16:14:37 +0100252 return rc;
253}
254