blob: cd3ab3a32e956fa44a3d991e40547f31e103bf47 [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>
41
42#include "smpp_smsc.h"
43
44
45static struct gsm_subscriber *subscr_by_dst(struct gsm_network *net,
46 uint8_t npi, uint8_t ton, const char *addr)
47{
48 struct gsm_subscriber *subscr = NULL;
49
50 switch (npi) {
51 case NPI_Land_Mobile_E212:
52 subscr = subscr_get_by_imsi(net, addr);
53 break;
54 case NPI_ISDN_E163_E164:
55 case NPI_Private:
56 subscr = subscr_get_by_extension(net, addr);
57 break;
58 default:
59 LOGP(DSMPP, LOGL_NOTICE, "Unsupported NPI: %u\n", npi);
60 break;
61 }
62
63 return subscr;
64}
65
66struct tlv_t *find_tlv(struct tlv_t *head, uint16_t tag)
67{
68 struct tlv_t *t;
69
70 for (t = head; t != NULL; t = t->next) {
71 if (t->tag == tag)
72 return t;
73 }
74 return NULL;
75}
76
77/* convert from submit_sm_t to gsm_sms */
78static int submit_to_sms(struct gsm_sms **psms, struct gsm_network *net,
79 const struct submit_sm_t *submit)
80{
81 struct gsm_subscriber *dest;
82 struct gsm_sms *sms;
83 struct tlv_t *t;
84 const uint8_t *sms_msg;
85 unsigned int sms_msg_len;
86
87 dest = subscr_by_dst(net, submit->dest_addr_npi,
88 submit->dest_addr_ton,
89 (const char *)submit->destination_addr);
90 if (!dest) {
91 LOGP(DSMS, LOGL_NOTICE, "SMPP SUBMIT-SM for unknown subscriber: "
92 "%s (NPI=%u)\n", submit->destination_addr,
93 submit->dest_addr_npi);
94 return ESME_RINVDSTADR;
95 }
96
97 t = find_tlv(submit->tlv, TLVID_message_payload);
98 if (t) {
99 if (submit->sm_length) {
100 /* ERROR: we cannot have botH! */
101 return ESME_ROPTPARNOTALLWD;
102 }
103 sms_msg = t->value.octet;
104 sms_msg_len = t->length;
105 } else if (submit->short_message && submit->sm_length) {
106 sms_msg = submit->short_message;
107 sms_msg_len = submit->sm_length;
108 } else {
109 sms_msg = NULL;
110 sms_msg_len = 0;
111 }
112
113 sms = sms_alloc();
114 sms->receiver = subscr_get(dest);
115 strncpy(sms->dest_addr, dest->extension, sizeof(sms->dest_addr)-1);
116 sms->sender = subscr_get_by_id(net, 1);
117
118 if (submit->esm_class & 0x40)
119 sms->ud_hdr_ind = 1;
120
121 if (submit->esm_class & 0x80) {
122 sms->reply_path_req = 1;
123#warning Implement reply path
124 }
125
126 switch (submit->data_coding) {
127 case 0x00:
128 case 0x01: /* GSM default alphabet */
129 sms->data_coding_scheme = GSM338_DCS_1111_7BIT;
130 strncpy(sms->text, (char *)sms_msg,
131 OSMO_MIN(sizeof(sms->text)-1, sms_msg_len));
132 sms->user_data_len = gsm_7bit_encode(sms->user_data, sms->text);
133 break;
134 case 0x02:
135 case 0x04: /* 8-bit binary */
136 sms->data_coding_scheme = GSM338_DCS_1111_8BIT_DATA;
137 memcpy(sms->user_data, sms_msg, sms_msg_len);
138 sms->user_data_len = sms_msg_len;
139 break;
140 case 0x80: /* UCS-2 */
141 sms->data_coding_scheme = (2 << 2);
142 memcpy(sms->user_data, sms_msg, submit->sm_length);
143 sms->user_data_len = sms_msg_len;
144 break;
145 /* FIXME */
146 default:
147 sms_free(sms);
148 return ESME_RUNKNOWNERR;
149 }
150
151 *psms = sms;
152 return ESME_ROK;
153}
154
155int handle_smpp_submit(struct osmo_esme *esme, struct submit_sm_t *submit,
156 struct submit_sm_resp_t *submit_r)
157{
158 struct gsm_sms *sms;
159 int rc = -1;
160
161 rc = submit_to_sms(&sms, esme->smsc->priv, submit);
162 if (rc != ESME_ROK) {
163 submit_r->command_status = rc;
164 return 0;
165 }
166 /* FIXME: TP-PID */
167
168 switch (submit->esm_class & 3) {
169 case 0: /* default */
170 case 1: /* datagram */
171 case 3: /* store-and-forward */
172 rc = db_sms_store(sms);
173 if (rc < 0) {
174 LOGP(DSMS, LOGL_ERROR, "SMPP SUBMIT-SM: Unable to "
175 "store SMS in database\n");
176 sms_free(sms);
177 submit_r->command_status = ESME_RSYSERR;
178 return 0;
179 }
180 strcpy((char *)submit_r->message_id, "msg_id_not_implemented");
181 LOGP(DSMS, LOGL_INFO, "SMPP SUBMIT-SM: Stored in DB\n");
182 rc = 0;
183 break;
184 case 2: /* forward (i.e. transaction) mode */
185 /* FIXME */
186 rc = 1; /* don't send any response yet */
187 break;
188 }
189 return rc;
190}
191
192
193int smpp_openbsc_init(struct gsm_network *net, uint16_t port)
194{
195 struct smsc *smsc = talloc_zero(net, struct smsc);
196 int rc;
197
198 smsc->priv = net;
199
200 rc = smpp_smsc_init(smsc, port);
201 if (rc < 0)
202 talloc_free(smsc);
203
204 return rc;
205}
206