blob: 34e24c513343e4bd185a4940ac16fe19a2e5eb20 [file] [log] [blame]
Harald Weltef1033cc2012-11-08 16:14:37 +01001/* SMPP 3.4 interface, SMSC-side implementation */
2/* (C) 2012 by Harald Welte <laforge@gnumonks.org>
3 *
Harald Welte995ff352013-07-13 16:35:32 +02004 * All Rights Reserved
Harald Weltef1033cc2012-11-08 16:14:37 +01005 *
Harald Welte995ff352013-07-13 16:35:32 +02006 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
Harald Weltef1033cc2012-11-08 16:14:37 +010010 *
Harald Welte995ff352013-07-13 16:35:32 +020011 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Affero General Public License for more details.
15 *
16 * You should have received a copy of the GNU Affero General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Harald Weltef1033cc2012-11-08 16:14:37 +010018 */
19
20
21#include <stdio.h>
22#include <unistd.h>
23#include <string.h>
24#include <stdint.h>
25#include <errno.h>
Daniel Willmann1fc8ec62014-01-17 15:17:36 +010026#include <limits.h>
Harald Weltef1033cc2012-11-08 16:14:37 +010027
28#include <sys/socket.h>
29#include <netinet/in.h>
30
31#include <smpp34.h>
32#include <smpp34_structs.h>
33#include <smpp34_params.h>
34
35#include <osmocom/core/utils.h>
36#include <osmocom/core/socket.h>
37#include <osmocom/core/msgb.h>
38#include <osmocom/core/logging.h>
39#include <osmocom/core/write_queue.h>
40#include <osmocom/core/talloc.h>
Keith Whyteb6713152020-01-11 11:55:21 +010041#include <osmocom/gsm/protocol/gsm_04_11.h>
Harald Weltef1033cc2012-11-08 16:14:37 +010042
Neels Hofmeyr90843962017-09-04 15:04:35 +020043#include <osmocom/msc/debug.h>
44#include <osmocom/msc/gsm_data.h>
Max5346f692022-07-28 14:19:22 +070045#include <osmocom/smpp/smpp_smsc.h>
Harald Welte4dbcdad2012-11-08 22:12:45 +010046
Harald Weltef1033cc2012-11-08 16:14:37 +010047enum emse_bind {
48 ESME_BIND_RX = 0x01,
49 ESME_BIND_TX = 0x02,
50};
51
Harald Weltee07b6a72012-11-23 19:02:37 +010052const struct value_string smpp_status_strs[] = {
53 { ESME_ROK, "No Error" },
54 { ESME_RINVMSGLEN, "Message Length is invalid" },
55 { ESME_RINVCMDLEN, "Command Length is invalid" },
56 { ESME_RINVCMDID, "Invalid Command ID" },
57 { ESME_RINVBNDSTS, "Incorrect BIND Status for given command" },
58 { ESME_RALYBND, "ESME Already in Bound State" },
59 { ESME_RINVPRTFLG, "Invalid Priority Flag" },
60 { ESME_RINVREGDLVFLG, "Invalid Registered Delivery Flag" },
61 { ESME_RSYSERR, "System Error" },
62 { ESME_RINVSRCADR, "Invalid Source Address" },
63 { ESME_RINVDSTADR, "Invalid Destination Address" },
64 { ESME_RINVMSGID, "Message ID is invalid" },
65 { ESME_RBINDFAIL, "Bind failed" },
66 { ESME_RINVPASWD, "Invalid Password" },
67 { ESME_RINVSYSID, "Invalid System ID" },
68 { ESME_RCANCELFAIL, "Cancel SM Failed" },
69 { ESME_RREPLACEFAIL, "Replace SM Failed" },
70 { ESME_RMSGQFUL, "Message Queue Full" },
71 { ESME_RINVSERTYP, "Invalid Service Type" },
72 { ESME_RINVNUMDESTS, "Invalid number of destinations" },
73 { ESME_RINVDLNAME, "Invalid Distribution List name" },
74 { ESME_RINVDESTFLAG, "Destination flag is invalid" },
75 { ESME_RINVSUBREP, "Invalid submit with replace request" },
76 { ESME_RINVESMCLASS, "Invalid esm_class field data" },
77 { ESME_RCNTSUBDL, "Cannot Submit to Distribution List" },
78 { ESME_RSUBMITFAIL, "submit_sm or submit_multi failed" },
79 { ESME_RINVSRCTON, "Invalid Source address TON" },
80 { ESME_RINVSRCNPI, "Invalid Sourec address NPI" },
81 { ESME_RINVDSTTON, "Invalid Destination address TON" },
82 { ESME_RINVDSTNPI, "Invalid Desetination address NPI" },
83 { ESME_RINVSYSTYP, "Invalid system_type field" },
84 { ESME_RINVREPFLAG, "Invalid replace_if_present field" },
85 { ESME_RINVNUMMSGS, "Invalid number of messages" },
86 { ESME_RTHROTTLED, "Throttling error (ESME has exceeded message limits)" },
87 { ESME_RINVSCHED, "Invalid Scheduled Delivery Time" },
88 { ESME_RINVEXPIRY, "Invalid message validity period (Expiry time)" },
89 { ESME_RINVDFTMSGID, "Predefined Message Invalid or Not Found" },
90 { ESME_RX_T_APPN, "ESME Receiver Temporary App Error Code" },
91 { ESME_RX_P_APPN, "ESME Receiver Permanent App Error Code" },
92 { ESME_RX_R_APPN, "ESME Receiver Reject Message Error Code" },
93 { ESME_RQUERYFAIL, "query_sm request failed" },
94 { ESME_RINVOPTPARSTREAM,"Error in the optional part of the PDU Body" },
95 { ESME_ROPTPARNOTALLWD, "Optional Parameter not allowed" },
96 { ESME_RINVPARLEN, "Invalid Parameter Length" },
97 { ESME_RMISSINGOPTPARAM,"Expected Optional Parameter missing" },
98 { ESME_RINVOPTPARAMVAL, "Invalid Optional Parameter Value" },
99 { ESME_RDELIVERYFAILURE,"Delivery Failure (used for data_sm_resp)" },
100 { ESME_RUNKNOWNERR, "Unknown Error" },
101 { 0, NULL }
102};
103
104/*! \brief compare if two SMPP addresses are equal */
105int smpp_addr_eq(const struct osmo_smpp_addr *a,
106 const struct osmo_smpp_addr *b)
107{
108 if (a->ton == b->ton &&
109 a->npi == b->npi &&
110 !strcmp(a->addr, b->addr))
111 return 1;
112
113 return 0;
114}
115
116
Harald Welte338e3b32012-11-20 22:22:04 +0100117struct osmo_smpp_acl *smpp_acl_by_system_id(struct smsc *smsc,
118 const char *sys_id)
119{
120 struct osmo_smpp_acl *acl;
121
122 llist_for_each_entry(acl, &smsc->acl_list, list) {
123 if (!strcmp(acl->system_id, sys_id))
124 return acl;
125 }
126
127 return NULL;
128}
129
130struct osmo_smpp_acl *smpp_acl_alloc(struct smsc *smsc, const char *sys_id)
131{
132 struct osmo_smpp_acl *acl;
133
134 if (strlen(sys_id) > SMPP_SYS_ID_LEN)
135 return NULL;
136
137 if (smpp_acl_by_system_id(smsc, sys_id))
138 return NULL;
139
140 acl = talloc_zero(smsc, struct osmo_smpp_acl);
141 if (!acl)
142 return NULL;
143
144 acl->smsc = smsc;
145 strcpy(acl->system_id, sys_id);
Keithc6d219c2019-01-17 01:01:59 +0100146 acl->alert_notifications = 1;
Harald Weltee07b6a72012-11-23 19:02:37 +0100147 INIT_LLIST_HEAD(&acl->route_list);
Harald Welte338e3b32012-11-20 22:22:04 +0100148
Harald Weltee07b6a72012-11-23 19:02:37 +0100149 llist_add_tail(&acl->list, &smsc->acl_list);
Harald Welte338e3b32012-11-20 22:22:04 +0100150
151 return acl;
152}
153
154void smpp_acl_delete(struct osmo_smpp_acl *acl)
155{
Harald Weltee07b6a72012-11-23 19:02:37 +0100156 struct osmo_smpp_route *r, *r2;
Harald Welte338e3b32012-11-20 22:22:04 +0100157
158 llist_del(&acl->list);
159
Harald Weltee07b6a72012-11-23 19:02:37 +0100160 /* kill any active ESMEs */
161 if (acl->esme) {
Max366a3402022-08-01 23:01:24 +0700162 struct esme *esme = acl->esme->esme;
Harald Weltee07b6a72012-11-23 19:02:37 +0100163 osmo_fd_unregister(&esme->wqueue.bfd);
164 close(esme->wqueue.bfd.fd);
165 esme->wqueue.bfd.fd = -1;
Max366a3402022-08-01 23:01:24 +0700166 smpp_esme_put(acl->esme);
Max2c6c74e2022-10-27 17:29:39 +0300167 acl->esme = NULL;
Harald Weltee07b6a72012-11-23 19:02:37 +0100168 }
169
170 /* delete all routes for this ACL */
171 llist_for_each_entry_safe(r, r2, &acl->route_list, list) {
172 llist_del(&r->list);
173 llist_del(&r->global_list);
174 talloc_free(r);
Harald Welte338e3b32012-11-20 22:22:04 +0100175 }
176
177 talloc_free(acl);
178}
179
Harald Weltee07b6a72012-11-23 19:02:37 +0100180static struct osmo_smpp_route *route_alloc(struct osmo_smpp_acl *acl)
181{
182 struct osmo_smpp_route *r;
183
184 r = talloc_zero(acl, struct osmo_smpp_route);
185 if (!r)
186 return NULL;
187
188 llist_add_tail(&r->list, &acl->route_list);
189 llist_add_tail(&r->global_list, &acl->smsc->route_list);
190
191 return r;
192}
193
194int smpp_route_pfx_add(struct osmo_smpp_acl *acl,
195 const struct osmo_smpp_addr *pfx)
196{
197 struct osmo_smpp_route *r;
198
199 llist_for_each_entry(r, &acl->route_list, list) {
200 if (r->type == SMPP_ROUTE_PREFIX &&
201 smpp_addr_eq(&r->u.prefix, pfx))
202 return -EEXIST;
203 }
204
205 r = route_alloc(acl);
206 if (!r)
207 return -ENOMEM;
208 r->type = SMPP_ROUTE_PREFIX;
209 r->acl = acl;
210 memcpy(&r->u.prefix, pfx, sizeof(r->u.prefix));
211
212 return 0;
213}
214
215int smpp_route_pfx_del(struct osmo_smpp_acl *acl,
216 const struct osmo_smpp_addr *pfx)
217{
218 struct osmo_smpp_route *r, *r2;
219
220 llist_for_each_entry_safe(r, r2, &acl->route_list, list) {
221 if (r->type == SMPP_ROUTE_PREFIX &&
222 smpp_addr_eq(&r->u.prefix, pfx)) {
223 llist_del(&r->list);
224 talloc_free(r);
225 return 0;
226 }
227 }
228
229 return -ENODEV;
230}
231
Harald Welte338e3b32012-11-20 22:22:04 +0100232
Harald Weltee94db492012-11-08 20:11:05 +0100233/*! \brief increaes the use/reference count */
Max366a3402022-08-01 23:01:24 +0700234void smpp_esme_get(struct smpp_esme *esme)
Harald Weltee94db492012-11-08 20:11:05 +0100235{
236 esme->use++;
237}
238
Max366a3402022-08-01 23:01:24 +0700239static void esme_destroy(struct smpp_esme *esme)
Harald Weltee94db492012-11-08 20:11:05 +0100240{
Max366a3402022-08-01 23:01:24 +0700241 osmo_wqueue_clear(&esme->esme->wqueue);
242 if (esme->esme->wqueue.bfd.fd >= 0) {
243 osmo_fd_unregister(&esme->esme->wqueue.bfd);
244 close(esme->esme->wqueue.bfd.fd);
Harald Weltee94db492012-11-08 20:11:05 +0100245 }
Pablo Neira Ayuso93ffbd02017-05-04 18:44:22 +0200246 smpp_cmd_flush_pending(esme);
Harald Weltee94db492012-11-08 20:11:05 +0100247 llist_del(&esme->list);
Harald Weltece969282018-04-14 15:04:28 +0200248 if (esme->acl)
249 esme->acl->esme = NULL;
Harald Weltee94db492012-11-08 20:11:05 +0100250 talloc_free(esme);
251}
252
Max4743a772022-08-01 23:16:52 +0700253uint32_t esme_inc_seq_nr(struct esme *esme)
Harald Weltee07b6a72012-11-23 19:02:37 +0100254{
255 esme->own_seq_nr++;
256 if (esme->own_seq_nr > 0x7fffffff)
257 esme->own_seq_nr = 1;
258
259 return esme->own_seq_nr;
260}
261
Harald Weltee94db492012-11-08 20:11:05 +0100262/*! \brief decrease the use/reference count, free if it is 0 */
Max366a3402022-08-01 23:01:24 +0700263void smpp_esme_put(struct smpp_esme *esme)
Harald Weltee94db492012-11-08 20:11:05 +0100264{
265 esme->use--;
266 if (esme->use <= 0)
267 esme_destroy(esme);
268}
269
Harald Weltee07b6a72012-11-23 19:02:37 +0100270/*! \brief try to find a SMPP route (ESME) for given destination */
Max366a3402022-08-01 23:01:24 +0700271int smpp_route(const struct smsc *smsc, const struct osmo_smpp_addr *dest, struct smpp_esme **pesme)
Harald Weltee07b6a72012-11-23 19:02:37 +0100272{
273 struct osmo_smpp_route *r;
274 struct osmo_smpp_acl *acl = NULL;
275
276 DEBUGP(DSMPP, "Looking up route for (%u/%u/%s)\n",
277 dest->ton, dest->npi, dest->addr);
278
279 /* search for a specific route */
280 llist_for_each_entry(r, &smsc->route_list, global_list) {
281 switch (r->type) {
282 case SMPP_ROUTE_PREFIX:
283 DEBUGP(DSMPP, "Checking prefix route (%u/%u/%s)->%s\n",
284 r->u.prefix.ton, r->u.prefix.npi, r->u.prefix.addr,
285 r->acl->system_id);
286 if (r->u.prefix.ton == dest->ton &&
287 r->u.prefix.npi == dest->npi &&
288 !strncmp(r->u.prefix.addr, dest->addr,
289 strlen(r->u.prefix.addr))) {
290 DEBUGP(DSMPP, "Found prefix route ACL\n");
291 acl = r->acl;
292 }
293 break;
294 default:
295 break;
296 }
297
298 if (acl)
299 break;
300 }
301
302 if (!acl) {
303 /* check for default route */
304 if (smsc->def_route) {
305 DEBUGP(DSMPP, "Using existing default route\n");
306 acl = smsc->def_route;
307 }
308 }
309
310 if (acl && acl->esme) {
Max366a3402022-08-01 23:01:24 +0700311 struct smpp_esme *esme;
Harald Weltee07b6a72012-11-23 19:02:37 +0100312 DEBUGP(DSMPP, "ACL even has ESME, we can route to it!\n");
313 esme = acl->esme;
Benoit Bolseed34ed572017-07-05 11:46:55 +0200314 if (esme->bind_flags & ESME_BIND_RX) {
315 *pesme = esme;
316 return 0;
317 } else
Max366a3402022-08-01 23:01:24 +0700318 LOGPESME(esme->esme, LOGL_NOTICE, "is matching route, but not bound for Rx, discarding MO SMS\n");
Harald Weltee07b6a72012-11-23 19:02:37 +0100319 }
320
Benoit Bolseed34ed572017-07-05 11:46:55 +0200321 *pesme = NULL;
322 if (acl)
Keith Whyteb6713152020-01-11 11:55:21 +0100323 return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
Benoit Bolseed34ed572017-07-05 11:46:55 +0200324 else
Keith Whyteb6713152020-01-11 11:55:21 +0100325 return GSM411_RP_CAUSE_MO_NUM_UNASSIGNED;
Harald Weltee07b6a72012-11-23 19:02:37 +0100326}
327
Harald Weltee94db492012-11-08 20:11:05 +0100328/*! \brief pack a libsmpp34 data strcutrure and send it to the ESME */
Max4743a772022-08-01 23:16:52 +0700329int pack_and_send(struct esme *esme, uint32_t type, void *ptr)
Harald Weltef1033cc2012-11-08 16:14:37 +0100330{
Harald Weltebf254f62022-05-16 17:42:17 +0200331 struct msgb *msg;
Harald Weltef1033cc2012-11-08 16:14:37 +0100332 int rc, rlen;
Harald Weltebf254f62022-05-16 17:42:17 +0200333
334 /* the socket was closed. Avoid allocating + enqueueing msgb, see
335 * https://osmocom.org/issues/3278 */
336 if (esme->wqueue.bfd.fd == -1)
337 return -EIO;
338
339 msg = msgb_alloc(4096, "SMPP_Tx");
Harald Weltef1033cc2012-11-08 16:14:37 +0100340 if (!msg)
341 return -ENOMEM;
342
343 rc = smpp34_pack(type, msg->tail, msgb_tailroom(msg), &rlen, ptr);
344 if (rc != 0) {
Max62977d02022-08-01 22:50:52 +0700345 LOGPESMERR(esme, "during smpp34_pack()\n");
Harald Weltef1033cc2012-11-08 16:14:37 +0100346 msgb_free(msg);
347 return -EINVAL;
348 }
349 msgb_put(msg, rlen);
350
Holger Hans Peter Freytherfd603ed2015-03-28 18:09:31 +0100351 if (osmo_wqueue_enqueue(&esme->wqueue, msg) != 0) {
Max62977d02022-08-01 22:50:52 +0700352 LOGPESME(esme, LOGL_ERROR, "Write queue full. Dropping message\n");
Holger Hans Peter Freytherfd603ed2015-03-28 18:09:31 +0100353 msgb_free(msg);
354 return -EAGAIN;
355 }
356 return 0;
Harald Weltef1033cc2012-11-08 16:14:37 +0100357}
358
Harald Weltee94db492012-11-08 20:11:05 +0100359/*! \brief transmit a generic NACK to a remote ESME */
Max366a3402022-08-01 23:01:24 +0700360static int smpp_tx_gen_nack(struct esme *esme, uint32_t seq, uint32_t status)
Harald Weltef1033cc2012-11-08 16:14:37 +0100361{
362 struct generic_nack_t nack;
Harald Welte874f9f12012-11-09 13:02:49 +0100363 char buf[SMALL_BUFF];
Harald Weltef1033cc2012-11-08 16:14:37 +0100364
365 nack.command_length = 0;
366 nack.command_id = GENERIC_NACK;
367 nack.sequence_number = seq;
368 nack.command_status = status;
369
Max62977d02022-08-01 22:50:52 +0700370 LOGPESME(esme, LOGL_ERROR, "Tx GENERIC NACK: %s\n", str_command_status(status, buf));
Harald Welte874f9f12012-11-09 13:02:49 +0100371
Harald Weltef1033cc2012-11-08 16:14:37 +0100372 return PACK_AND_SEND(esme, &nack);
373}
374
Harald Weltee94db492012-11-08 20:11:05 +0100375/*! \brief retrieve SMPP sequence number from a msgb */
Harald Weltef1033cc2012-11-08 16:14:37 +0100376static inline uint32_t smpp_msgb_seq(struct msgb *msg)
377{
378 uint8_t *tmp = msgb_data(msg);
379 return ntohl(*(uint32_t *)tmp);
380}
381
Harald Weltee94db492012-11-08 20:11:05 +0100382/*! \brief handle an incoming SMPP generic NACK */
Max366a3402022-08-01 23:01:24 +0700383static int smpp_handle_gen_nack(struct esme *esme, struct msgb *msg)
Harald Weltef1033cc2012-11-08 16:14:37 +0100384{
385 struct generic_nack_t nack;
386 char buf[SMALL_BUFF];
387 int rc;
388
Harald Welte4dbcdad2012-11-08 22:12:45 +0100389 SMPP34_UNPACK(rc, GENERIC_NACK, &nack, msgb_data(msg),
390 msgb_length(msg));
Harald Welte874f9f12012-11-09 13:02:49 +0100391 if (rc < 0) {
Max62977d02022-08-01 22:50:52 +0700392 LOGPESMERR(esme, "in smpp34_unpack()\n");
Harald Weltef1033cc2012-11-08 16:14:37 +0100393 return rc;
Harald Welte874f9f12012-11-09 13:02:49 +0100394 }
Harald Weltef1033cc2012-11-08 16:14:37 +0100395
Max62977d02022-08-01 22:50:52 +0700396 LOGPESME(esme, LOGL_ERROR, "Rx GENERIC NACK: %s\n", str_command_status(nack.command_status, buf));
Harald Weltef1033cc2012-11-08 16:14:37 +0100397
398 return 0;
399}
400
Max366a3402022-08-01 23:01:24 +0700401static int _process_bind(struct smpp_esme *esme, uint8_t if_version,
Harald Weltee07b6a72012-11-23 19:02:37 +0100402 uint32_t bind_flags, const char *sys_id,
403 const char *passwd)
404{
405 struct osmo_smpp_acl *acl;
406
407 if (if_version != SMPP_VERSION)
408 return ESME_RSYSERR;
409
410 if (esme->bind_flags)
411 return ESME_RALYBND;
412
413 esme->smpp_version = if_version;
Max366a3402022-08-01 23:01:24 +0700414 snprintf(esme->esme->system_id, sizeof(esme->esme->system_id), "%s", sys_id);
Harald Weltee07b6a72012-11-23 19:02:37 +0100415
Max366a3402022-08-01 23:01:24 +0700416 acl = smpp_acl_by_system_id(esme->smsc, esme->esme->system_id);
Harald Weltee07b6a72012-11-23 19:02:37 +0100417 if (!esme->smsc->accept_all) {
418 if (!acl) {
419 /* This system is unknown */
420 return ESME_RINVSYSID;
421 } else {
422 if (strlen(acl->passwd) &&
423 strcmp(acl->passwd, passwd)) {
424 return ESME_RINVPASWD;
425 }
426 }
427 }
428 if (acl) {
429 esme->acl = acl;
430 acl->esme = esme;
431 }
432
433 esme->bind_flags = bind_flags;
434
435 return ESME_ROK;
436}
437
438
Harald Weltee94db492012-11-08 20:11:05 +0100439/*! \brief handle an incoming SMPP BIND RECEIVER */
Max366a3402022-08-01 23:01:24 +0700440static int smpp_handle_bind_rx(struct smpp_esme *esme, struct msgb *msg)
Harald Weltef1033cc2012-11-08 16:14:37 +0100441{
442 struct bind_receiver_t bind;
443 struct bind_receiver_resp_t bind_r;
444 int rc;
445
Harald Welte4dbcdad2012-11-08 22:12:45 +0100446 SMPP34_UNPACK(rc, BIND_RECEIVER, &bind, msgb_data(msg),
Harald Weltef1033cc2012-11-08 16:14:37 +0100447 msgb_length(msg));
Harald Welte874f9f12012-11-09 13:02:49 +0100448 if (rc < 0) {
Max366a3402022-08-01 23:01:24 +0700449 LOGPESMERR(esme->esme, "in smpp34_unpack()\n");
Harald Weltef1033cc2012-11-08 16:14:37 +0100450 return rc;
Harald Welte874f9f12012-11-09 13:02:49 +0100451 }
Harald Weltef1033cc2012-11-08 16:14:37 +0100452
453 INIT_RESP(BIND_TRANSMITTER_RESP, &bind_r, &bind);
454
Harald Welte874f9f12012-11-09 13:02:49 +0100455 LOGP(DSMPP, LOGL_INFO, "[%s] Rx BIND Rx from (Version %02x)\n",
Harald Weltef1033cc2012-11-08 16:14:37 +0100456 bind.system_id, bind.interface_version);
457
Harald Weltee07b6a72012-11-23 19:02:37 +0100458 rc = _process_bind(esme, bind.interface_version, ESME_BIND_RX,
459 (const char *)bind.system_id, (const char *)bind.password);
460 bind_r.command_status = rc;
Harald Weltef1033cc2012-11-08 16:14:37 +0100461
Max366a3402022-08-01 23:01:24 +0700462 return PACK_AND_SEND(esme->esme, &bind_r);
Harald Weltef1033cc2012-11-08 16:14:37 +0100463}
464
Harald Weltee94db492012-11-08 20:11:05 +0100465/*! \brief handle an incoming SMPP BIND TRANSMITTER */
Max366a3402022-08-01 23:01:24 +0700466static int smpp_handle_bind_tx(struct smpp_esme *esme, struct msgb *msg)
Harald Weltef1033cc2012-11-08 16:14:37 +0100467{
468 struct bind_transmitter_t bind;
469 struct bind_transmitter_resp_t bind_r;
Oliver Smith79d824f2023-06-22 11:42:23 +0200470 struct tlv_t tlv = {};
Harald Weltef1033cc2012-11-08 16:14:37 +0100471 int rc;
472
Harald Welte4dbcdad2012-11-08 22:12:45 +0100473 SMPP34_UNPACK(rc, BIND_TRANSMITTER, &bind, msgb_data(msg),
Harald Weltef1033cc2012-11-08 16:14:37 +0100474 msgb_length(msg));
475 if (rc < 0) {
Max366a3402022-08-01 23:01:24 +0700476 LOGPESMERR(esme->esme, "in smpp34_unpack()\n");
Harald Weltef1033cc2012-11-08 16:14:37 +0100477 return rc;
478 }
479
480 INIT_RESP(BIND_TRANSMITTER_RESP, &bind_r, &bind);
481
Harald Welte874f9f12012-11-09 13:02:49 +0100482 LOGP(DSMPP, LOGL_INFO, "[%s] Rx BIND Tx (Version %02x)\n",
Harald Weltef1033cc2012-11-08 16:14:37 +0100483 bind.system_id, bind.interface_version);
484
Harald Weltee07b6a72012-11-23 19:02:37 +0100485 rc = _process_bind(esme, bind.interface_version, ESME_BIND_TX,
486 (const char *)bind.system_id, (const char *)bind.password);
487 bind_r.command_status = rc;
Harald Weltef1033cc2012-11-08 16:14:37 +0100488
489 /* build response */
Neels Hofmeyr26c218d2017-12-18 04:08:02 +0100490 osmo_strlcpy((char*)bind_r.system_id, esme->smsc->system_id, sizeof(bind_r.system_id));
Harald Weltef1033cc2012-11-08 16:14:37 +0100491
492 /* add interface version TLV */
493 tlv.tag = TLVID_sc_interface_version;
494 tlv.length = sizeof(uint8_t);
495 tlv.value.val16 = esme->smpp_version;
496 build_tlv(&bind_r.tlv, &tlv);
497
Max366a3402022-08-01 23:01:24 +0700498 rc = PACK_AND_SEND(esme->esme, &bind_r);
Harald Welte5dede762019-04-09 23:58:55 +0200499 destroy_tlv(bind_r.tlv);
500 return rc;
Harald Weltef1033cc2012-11-08 16:14:37 +0100501}
502
Harald Weltee94db492012-11-08 20:11:05 +0100503/*! \brief handle an incoming SMPP BIND TRANSCEIVER */
Max366a3402022-08-01 23:01:24 +0700504static int smpp_handle_bind_trx(struct smpp_esme *esme, struct msgb *msg)
Harald Weltef1033cc2012-11-08 16:14:37 +0100505{
506 struct bind_transceiver_t bind;
507 struct bind_transceiver_resp_t bind_r;
508 int rc;
509
Harald Welte4dbcdad2012-11-08 22:12:45 +0100510 SMPP34_UNPACK(rc, BIND_TRANSCEIVER, &bind, msgb_data(msg),
Harald Weltef1033cc2012-11-08 16:14:37 +0100511 msgb_length(msg));
Harald Welte874f9f12012-11-09 13:02:49 +0100512 if (rc < 0) {
Max366a3402022-08-01 23:01:24 +0700513 LOGPESMERR(esme->esme, "in smpp34_unpack()\n");
Harald Weltef1033cc2012-11-08 16:14:37 +0100514 return rc;
Harald Welte874f9f12012-11-09 13:02:49 +0100515 }
Harald Weltef1033cc2012-11-08 16:14:37 +0100516
Harald Welte61e19352013-05-26 14:40:14 +0200517 INIT_RESP(BIND_TRANSCEIVER_RESP, &bind_r, &bind);
Harald Weltef1033cc2012-11-08 16:14:37 +0100518
Harald Welte874f9f12012-11-09 13:02:49 +0100519 LOGP(DSMPP, LOGL_INFO, "[%s] Rx BIND Trx (Version %02x)\n",
Harald Weltef1033cc2012-11-08 16:14:37 +0100520 bind.system_id, bind.interface_version);
521
Harald Weltee07b6a72012-11-23 19:02:37 +0100522 rc = _process_bind(esme, bind.interface_version, ESME_BIND_RX|ESME_BIND_TX,
523 (const char *)bind.system_id, (const char *)bind.password);
524 bind_r.command_status = rc;
Harald Weltef1033cc2012-11-08 16:14:37 +0100525
Max366a3402022-08-01 23:01:24 +0700526 return PACK_AND_SEND(esme->esme, &bind_r);
Harald Weltef1033cc2012-11-08 16:14:37 +0100527}
528
Harald Weltee94db492012-11-08 20:11:05 +0100529/*! \brief handle an incoming SMPP UNBIND */
Max366a3402022-08-01 23:01:24 +0700530static int smpp_handle_unbind(struct smpp_esme *esme, struct msgb *msg)
Harald Weltef1033cc2012-11-08 16:14:37 +0100531{
532 struct unbind_t unbind;
533 struct unbind_resp_t unbind_r;
534 int rc;
535
Harald Welte4dbcdad2012-11-08 22:12:45 +0100536 SMPP34_UNPACK(rc, UNBIND, &unbind, msgb_data(msg),
Harald Weltef1033cc2012-11-08 16:14:37 +0100537 msgb_length(msg));
Harald Welte874f9f12012-11-09 13:02:49 +0100538 if (rc < 0) {
Max366a3402022-08-01 23:01:24 +0700539 LOGPESMERR(esme->esme, "in smpp34_unpack()\n");
Harald Weltef1033cc2012-11-08 16:14:37 +0100540 return rc;
Harald Welte874f9f12012-11-09 13:02:49 +0100541 }
Harald Weltef1033cc2012-11-08 16:14:37 +0100542
543 INIT_RESP(UNBIND_RESP, &unbind_r, &unbind);
544
Max366a3402022-08-01 23:01:24 +0700545 LOGPESME(esme->esme, LOGL_INFO, "Rx UNBIND\n");
Harald Weltef1033cc2012-11-08 16:14:37 +0100546
547 if (esme->bind_flags == 0) {
548 unbind_r.command_status = ESME_RINVBNDSTS;
549 goto err;
550 }
551
552 esme->bind_flags = 0;
553err:
Max366a3402022-08-01 23:01:24 +0700554 return PACK_AND_SEND(esme->esme, &unbind_r);
Harald Weltef1033cc2012-11-08 16:14:37 +0100555}
556
Harald Weltee94db492012-11-08 20:11:05 +0100557/*! \brief handle an incoming SMPP ENQUIRE LINK */
Max366a3402022-08-01 23:01:24 +0700558static int smpp_handle_enq_link(struct smpp_esme *esme, struct msgb *msg)
Harald Weltef1033cc2012-11-08 16:14:37 +0100559{
560 struct enquire_link_t enq;
561 struct enquire_link_resp_t enq_r;
562 int rc;
563
Harald Welte4dbcdad2012-11-08 22:12:45 +0100564 SMPP34_UNPACK(rc, ENQUIRE_LINK, &enq, msgb_data(msg),
Harald Weltef1033cc2012-11-08 16:14:37 +0100565 msgb_length(msg));
Harald Welte874f9f12012-11-09 13:02:49 +0100566 if (rc < 0) {
Max366a3402022-08-01 23:01:24 +0700567 LOGPESMERR(esme->esme, "in smpp34_unpack()\n");
Harald Weltef1033cc2012-11-08 16:14:37 +0100568 return rc;
Harald Welte874f9f12012-11-09 13:02:49 +0100569 }
Harald Weltef1033cc2012-11-08 16:14:37 +0100570
Max366a3402022-08-01 23:01:24 +0700571 LOGPESME(esme->esme, LOGL_DEBUG, "Rx Enquire Link\n");
Harald Weltef1033cc2012-11-08 16:14:37 +0100572
573 INIT_RESP(ENQUIRE_LINK_RESP, &enq_r, &enq);
574
Max366a3402022-08-01 23:01:24 +0700575 LOGPESME(esme->esme, LOGL_DEBUG, "Tx Enquire Link Response\n");
Harald Welte874f9f12012-11-09 13:02:49 +0100576
Max366a3402022-08-01 23:01:24 +0700577 return PACK_AND_SEND(esme->esme, &enq_r);
Harald Weltef1033cc2012-11-08 16:14:37 +0100578}
579
Harald Weltee94db492012-11-08 20:11:05 +0100580/*! \brief send a SUBMIT-SM RESPONSE to a remote ESME */
Max366a3402022-08-01 23:01:24 +0700581int smpp_tx_submit_r(struct smpp_esme *esme, uint32_t sequence_nr,
Harald Welted4bdee72012-11-08 19:44:08 +0100582 uint32_t command_status, char *msg_id)
583{
584 struct submit_sm_resp_t submit_r;
585
586 memset(&submit_r, 0, sizeof(submit_r));
587 submit_r.command_length = 0;
588 submit_r.command_id = SUBMIT_SM_RESP;
589 submit_r.command_status = command_status;
590 submit_r.sequence_number= sequence_nr;
Harald Welte8a1b0562012-11-09 12:51:44 +0100591 snprintf((char *) submit_r.message_id, sizeof(submit_r.message_id), "%s", msg_id);
Harald Welted4bdee72012-11-08 19:44:08 +0100592
Max366a3402022-08-01 23:01:24 +0700593 return PACK_AND_SEND(esme->esme, &submit_r);
Harald Welted4bdee72012-11-08 19:44:08 +0100594}
595
Harald Welte8a1b0562012-11-09 12:51:44 +0100596static const struct value_string smpp_avail_strs[] = {
597 { 0, "Available" },
598 { 1, "Denied" },
599 { 2, "Unavailable" },
600 { 0, NULL }
601};
602
603/*! \brief send an ALERT_NOTIFICATION to a remote ESME */
Max366a3402022-08-01 23:01:24 +0700604int smpp_tx_alert(struct smpp_esme *esme, uint8_t ton, uint8_t npi,
Harald Welte8a1b0562012-11-09 12:51:44 +0100605 const char *addr, uint8_t avail_status)
606{
607 struct alert_notification_t alert;
608 struct tlv_t tlv;
Harald Welte5dede762019-04-09 23:58:55 +0200609 int rc;
Harald Welte8a1b0562012-11-09 12:51:44 +0100610
611 memset(&alert, 0, sizeof(alert));
612 alert.command_length = 0;
613 alert.command_id = ALERT_NOTIFICATION;
614 alert.command_status = ESME_ROK;
Max366a3402022-08-01 23:01:24 +0700615 alert.sequence_number = esme_inc_seq_nr(esme->esme);
Harald Welte8a1b0562012-11-09 12:51:44 +0100616 alert.source_addr_ton = ton;
617 alert.source_addr_npi = npi;
Harald Welte874f9f12012-11-09 13:02:49 +0100618 snprintf((char *)alert.source_addr, sizeof(alert.source_addr), "%s", addr);
Harald Welte8a1b0562012-11-09 12:51:44 +0100619
620 tlv.tag = TLVID_ms_availability_status;
621 tlv.length = sizeof(uint8_t);
622 tlv.value.val08 = avail_status;
623 build_tlv(&alert.tlv, &tlv);
624
Max366a3402022-08-01 23:01:24 +0700625 LOGPESME(esme->esme, LOGL_DEBUG, "Tx ALERT_NOTIFICATION (%s/%u/%u): %s\n",
Max62977d02022-08-01 22:50:52 +0700626 alert.source_addr, alert.source_addr_ton,
627 alert.source_addr_npi,
628 get_value_string(smpp_avail_strs, avail_status));
Harald Welte8a1b0562012-11-09 12:51:44 +0100629
Max366a3402022-08-01 23:01:24 +0700630 rc = PACK_AND_SEND(esme->esme, &alert);
Harald Welte5dede762019-04-09 23:58:55 +0200631 destroy_tlv(alert.tlv);
632 return rc;
Harald Welte8a1b0562012-11-09 12:51:44 +0100633}
634
Harald Weltee07b6a72012-11-23 19:02:37 +0100635/* \brief send a DELIVER-SM message to given ESME */
Max366a3402022-08-01 23:01:24 +0700636int smpp_tx_deliver(struct smpp_esme *esme, struct deliver_sm_t *deliver)
Harald Weltee07b6a72012-11-23 19:02:37 +0100637{
Max366a3402022-08-01 23:01:24 +0700638 deliver->sequence_number = esme_inc_seq_nr(esme->esme);
Harald Weltee07b6a72012-11-23 19:02:37 +0100639
Max366a3402022-08-01 23:01:24 +0700640 LOGPESME(esme->esme, LOGL_DEBUG, "Tx DELIVER-SM (from %s)\n", deliver->source_addr);
Pau Espin Pedrol95606642017-07-06 13:50:59 +0200641
Max366a3402022-08-01 23:01:24 +0700642 return PACK_AND_SEND(esme->esme, deliver);
Harald Weltee07b6a72012-11-23 19:02:37 +0100643}
644
645/*! \brief handle an incoming SMPP DELIVER-SM RESPONSE */
Max366a3402022-08-01 23:01:24 +0700646static int smpp_handle_deliver_resp(struct smpp_esme *esme, struct msgb *msg)
Harald Weltee07b6a72012-11-23 19:02:37 +0100647{
648 struct deliver_sm_resp_t deliver_r;
Pablo Neira Ayuso93ffbd02017-05-04 18:44:22 +0200649 struct osmo_smpp_cmd *cmd;
Harald Weltee07b6a72012-11-23 19:02:37 +0100650 int rc;
651
652 memset(&deliver_r, 0, sizeof(deliver_r));
653 SMPP34_UNPACK(rc, DELIVER_SM_RESP, &deliver_r, msgb_data(msg),
654 msgb_length(msg));
655 if (rc < 0) {
Max366a3402022-08-01 23:01:24 +0700656 LOGPESMERR(esme->esme, "in smpp34_unpack()\n");
Harald Weltee07b6a72012-11-23 19:02:37 +0100657 return rc;
658 }
659
Pablo Neira Ayuso93ffbd02017-05-04 18:44:22 +0200660 cmd = smpp_cmd_find_by_seqnum(esme, deliver_r.sequence_number);
661 if (!cmd) {
Max366a3402022-08-01 23:01:24 +0700662 LOGPESME(esme->esme, LOGL_ERROR, "Rx DELIVER-SM RESP !? (%s)\n",
Max62977d02022-08-01 22:50:52 +0700663 get_value_string(smpp_status_strs, deliver_r.command_status));
Pablo Neira Ayuso93ffbd02017-05-04 18:44:22 +0200664 return -1;
665 }
666
Pablo Neira Ayuso93ffbd02017-05-04 18:44:22 +0200667 if (deliver_r.command_status == ESME_ROK)
668 smpp_cmd_ack(cmd);
669 else
Keith320960c2017-05-13 23:38:52 +0200670 smpp_cmd_err(cmd, deliver_r.command_status);
Pablo Neira Ayuso93ffbd02017-05-04 18:44:22 +0200671
Max366a3402022-08-01 23:01:24 +0700672 LOGPESME(esme->esme, LOGL_INFO, "Rx DELIVER-SM RESP (%s)\n",
Max62977d02022-08-01 22:50:52 +0700673 get_value_string(smpp_status_strs, deliver_r.command_status));
Harald Weltee07b6a72012-11-23 19:02:37 +0100674
675 return 0;
676}
677
Harald Weltee94db492012-11-08 20:11:05 +0100678/*! \brief handle an incoming SMPP SUBMIT-SM */
Max366a3402022-08-01 23:01:24 +0700679static int smpp_handle_submit(struct smpp_esme *esme, struct msgb *msg)
Harald Weltef1033cc2012-11-08 16:14:37 +0100680{
681 struct submit_sm_t submit;
682 struct submit_sm_resp_t submit_r;
683 int rc;
684
Harald Welte4dbcdad2012-11-08 22:12:45 +0100685 memset(&submit, 0, sizeof(submit));
686 SMPP34_UNPACK(rc, SUBMIT_SM, &submit, msgb_data(msg),
Harald Weltef1033cc2012-11-08 16:14:37 +0100687 msgb_length(msg));
Harald Welte874f9f12012-11-09 13:02:49 +0100688 if (rc < 0) {
Max366a3402022-08-01 23:01:24 +0700689 LOGPESMERR(esme->esme, "in smpp34_unpack()\n");
Harald Weltef1033cc2012-11-08 16:14:37 +0100690 return rc;
Harald Welte874f9f12012-11-09 13:02:49 +0100691 }
Harald Weltef1033cc2012-11-08 16:14:37 +0100692
693 INIT_RESP(SUBMIT_SM_RESP, &submit_r, &submit);
694
695 if (!(esme->bind_flags & ESME_BIND_TX)) {
696 submit_r.command_status = ESME_RINVBNDSTS;
Keith Whytec54ce6a2023-07-21 20:09:08 +0100697 destroy_tlv(submit.tlv);
Max366a3402022-08-01 23:01:24 +0700698 return PACK_AND_SEND(esme->esme, &submit_r);
Harald Weltef1033cc2012-11-08 16:14:37 +0100699 }
700
Max366a3402022-08-01 23:01:24 +0700701 LOGPESME(esme->esme, LOGL_INFO, "Rx SUBMIT-SM (%s/%u/%u)\n",
Max62977d02022-08-01 22:50:52 +0700702 submit.destination_addr, submit.dest_addr_ton, submit.dest_addr_npi);
Harald Weltef1033cc2012-11-08 16:14:37 +0100703
704 INIT_RESP(SUBMIT_SM_RESP, &submit_r, &submit);
705
706 rc = handle_smpp_submit(esme, &submit, &submit_r);
Keith Whytec54ce6a2023-07-21 20:09:08 +0100707 destroy_tlv(submit.tlv);
Harald Weltef1033cc2012-11-08 16:14:37 +0100708 if (rc == 0)
Max366a3402022-08-01 23:01:24 +0700709 return PACK_AND_SEND(esme->esme, &submit_r);
Harald Weltef1033cc2012-11-08 16:14:37 +0100710
711 return rc;
712}
713
Harald Weltee94db492012-11-08 20:11:05 +0100714/*! \brief one complete SMPP PDU from the ESME has been received */
Max366a3402022-08-01 23:01:24 +0700715static int smpp_pdu_rx(struct smpp_esme *esme, struct msgb *msg __uses)
Harald Weltef1033cc2012-11-08 16:14:37 +0100716{
717 uint32_t cmd_id = smpp_msgb_cmdid(msg);
718 int rc = 0;
719
Max366a3402022-08-01 23:01:24 +0700720 LOGPESME(esme->esme, LOGL_DEBUG, "smpp_pdu_rx(%s)\n", msgb_hexdump(msg));
Harald Weltef1033cc2012-11-08 16:14:37 +0100721
722 switch (cmd_id) {
723 case GENERIC_NACK:
Max366a3402022-08-01 23:01:24 +0700724 rc = smpp_handle_gen_nack(esme->esme, msg);
Harald Weltef1033cc2012-11-08 16:14:37 +0100725 break;
726 case BIND_RECEIVER:
727 rc = smpp_handle_bind_rx(esme, msg);
728 break;
729 case BIND_TRANSMITTER:
730 rc = smpp_handle_bind_tx(esme, msg);
731 break;
732 case BIND_TRANSCEIVER:
733 rc = smpp_handle_bind_trx(esme, msg);
734 break;
735 case UNBIND:
736 rc = smpp_handle_unbind(esme, msg);
737 break;
738 case ENQUIRE_LINK:
739 rc = smpp_handle_enq_link(esme, msg);
740 break;
741 case SUBMIT_SM:
742 rc = smpp_handle_submit(esme, msg);
743 break;
Harald Weltee07b6a72012-11-23 19:02:37 +0100744 case DELIVER_SM_RESP:
745 rc = smpp_handle_deliver_resp(esme, msg);
746 break;
Harald Weltef1033cc2012-11-08 16:14:37 +0100747 case DELIVER_SM:
748 break;
749 case DATA_SM:
750 break;
751 case CANCEL_SM:
752 case QUERY_SM:
753 case REPLACE_SM:
754 case SUBMIT_MULTI:
Max366a3402022-08-01 23:01:24 +0700755 LOGPESME(esme->esme, LOGL_NOTICE, "Unimplemented PDU Command 0x%08x\n", cmd_id);
Harald Weltef1033cc2012-11-08 16:14:37 +0100756 break;
757 default:
Max366a3402022-08-01 23:01:24 +0700758 LOGPESME(esme->esme, LOGL_ERROR, "Unknown PDU Command 0x%08x\n", cmd_id);
759 rc = smpp_tx_gen_nack(esme->esme, smpp_msgb_seq(msg), ESME_RINVCMDID);
Harald Weltef1033cc2012-11-08 16:14:37 +0100760 break;
761 }
762
763 return rc;
764}
765
Daniel Willmanna4540b22014-01-17 15:17:36 +0100766/* This macro should be called after a call to read() in the read_cb of an
767 * osmo_fd to properly check for errors.
768 * rc is the return value of read, err_label is the label to jump to in case of
769 * an error. The code there should handle closing the connection.
770 * FIXME: This code should go in libosmocore utils.h so it can be used by other
771 * projects as well.
772 * */
773#define OSMO_FD_CHECK_READ(rc, err_label) \
774 if (rc < 0) { \
775 /* EINTR is a non-fatal error, just try again */ \
776 if (errno == EINTR) \
777 return 0; \
778 goto err_label; \
779 } else if (rc == 0) { \
780 goto err_label; \
781 }
782
Harald Weltee94db492012-11-08 20:11:05 +0100783/* !\brief call-back when per-ESME TCP socket has some data to be read */
Harald Weltef1033cc2012-11-08 16:14:37 +0100784static int esme_link_read_cb(struct osmo_fd *ofd)
785{
Max366a3402022-08-01 23:01:24 +0700786 struct smpp_esme *e = ofd->data;
787 struct esme *esme = e->esme;
Harald Weltef1033cc2012-11-08 16:14:37 +0100788 uint32_t len;
789 uint8_t *lenptr = (uint8_t *) &len;
790 uint8_t *cur;
791 struct msgb *msg;
Daniel Willmann1fc8ec62014-01-17 15:17:36 +0100792 ssize_t rdlen, rc;
Harald Weltef1033cc2012-11-08 16:14:37 +0100793
794 switch (esme->read_state) {
795 case READ_ST_IN_LEN:
796 rdlen = sizeof(uint32_t) - esme->read_idx;
797 rc = read(ofd->fd, lenptr + esme->read_idx, rdlen);
Daniel Willmanna4540b22014-01-17 15:17:36 +0100798 if (rc < 0)
Max62977d02022-08-01 22:50:52 +0700799 LOGPESME(esme, LOGL_ERROR, "read returned %zd (%s)\n", rc, strerror(errno));
Daniel Willmanna4540b22014-01-17 15:17:36 +0100800 OSMO_FD_CHECK_READ(rc, dead_socket);
801
802 esme->read_idx += rc;
803
Harald Weltef1033cc2012-11-08 16:14:37 +0100804 if (esme->read_idx >= sizeof(uint32_t)) {
805 esme->read_len = ntohl(len);
Daniel Willmann1fc8ec62014-01-17 15:17:36 +0100806 if (esme->read_len < 8 || esme->read_len > UINT16_MAX) {
Max62977d02022-08-01 22:50:52 +0700807 LOGPESME(esme, LOGL_ERROR, "length invalid %u\n", esme->read_len);
Daniel Willmannb6f01e72014-01-17 15:17:36 +0100808 goto dead_socket;
809 }
810
Harald Weltef1033cc2012-11-08 16:14:37 +0100811 msg = msgb_alloc(esme->read_len, "SMPP Rx");
812 if (!msg)
813 return -ENOMEM;
814 esme->read_msg = msg;
815 cur = msgb_put(msg, sizeof(uint32_t));
816 memcpy(cur, lenptr, sizeof(uint32_t));
817 esme->read_state = READ_ST_IN_MSG;
818 esme->read_idx = sizeof(uint32_t);
819 }
820 break;
821 case READ_ST_IN_MSG:
822 msg = esme->read_msg;
823 rdlen = esme->read_len - esme->read_idx;
824 rc = read(ofd->fd, msg->tail, OSMO_MIN(rdlen, msgb_tailroom(msg)));
Daniel Willmanna4540b22014-01-17 15:17:36 +0100825 if (rc < 0)
Max62977d02022-08-01 22:50:52 +0700826 LOGPESME(esme, LOGL_ERROR, "read returned %zd (%s)\n",
827 rc, strerror(errno));
Daniel Willmanna4540b22014-01-17 15:17:36 +0100828 OSMO_FD_CHECK_READ(rc, dead_socket);
829
830 esme->read_idx += rc;
831 msgb_put(msg, rc);
Harald Weltef1033cc2012-11-08 16:14:37 +0100832
833 if (esme->read_idx >= esme->read_len) {
Max366a3402022-08-01 23:01:24 +0700834 rc = smpp_pdu_rx(e, esme->read_msg);
Holger Hans Peter Freytherd7b22c62013-04-29 09:11:02 +0200835 msgb_free(esme->read_msg);
Harald Weltef1033cc2012-11-08 16:14:37 +0100836 esme->read_msg = NULL;
837 esme->read_idx = 0;
838 esme->read_len = 0;
839 esme->read_state = READ_ST_IN_LEN;
840 }
841 break;
842 }
843
844 return 0;
845dead_socket:
846 msgb_free(esme->read_msg);
Harald Weltee94db492012-11-08 20:11:05 +0100847 osmo_fd_unregister(&esme->wqueue.bfd);
848 close(esme->wqueue.bfd.fd);
849 esme->wqueue.bfd.fd = -1;
Max366a3402022-08-01 23:01:24 +0700850 if (e->acl)
851 e->acl->esme = NULL;
852 smpp_esme_put(e);
Harald Weltef1033cc2012-11-08 16:14:37 +0100853
Harald Welte022193d2022-05-16 17:31:36 +0200854 return -EBADF;
Harald Weltef1033cc2012-11-08 16:14:37 +0100855}
856
857/* call-back of write queue once it wishes to write a message to the socket */
Holger Hans Peter Freyther5ecbc932013-07-27 18:39:30 +0200858static int esme_link_write_cb(struct osmo_fd *ofd, struct msgb *msg)
Harald Weltef1033cc2012-11-08 16:14:37 +0100859{
Max366a3402022-08-01 23:01:24 +0700860 struct smpp_esme *esme = ofd->data;
Harald Weltef1033cc2012-11-08 16:14:37 +0100861 int rc;
862
863 rc = write(ofd->fd, msgb_data(msg), msgb_length(msg));
864 if (rc == 0) {
Max366a3402022-08-01 23:01:24 +0700865 osmo_fd_unregister(&esme->esme->wqueue.bfd);
866 close(esme->esme->wqueue.bfd.fd);
867 esme->esme->wqueue.bfd.fd = -1;
Harald Weltece969282018-04-14 15:04:28 +0200868 if (esme->acl)
869 esme->acl->esme = NULL;
Harald Weltee94db492012-11-08 20:11:05 +0100870 smpp_esme_put(esme);
Harald Weltef1033cc2012-11-08 16:14:37 +0100871 } else if (rc < msgb_length(msg)) {
Max366a3402022-08-01 23:01:24 +0700872 LOGPESME(esme->esme, LOGL_ERROR, "Short write\n");
Holger Hans Peter Freyther5ecbc932013-07-27 18:39:30 +0200873 return -1;
Harald Weltef1033cc2012-11-08 16:14:37 +0100874 }
Holger Hans Peter Freyther5ecbc932013-07-27 18:39:30 +0200875
876 return 0;
Harald Weltef1033cc2012-11-08 16:14:37 +0100877}
878
Max366a3402022-08-01 23:01:24 +0700879struct esme *esme_alloc(void *ctx)
880{
881 struct esme *e = talloc_zero(ctx, struct esme);
882 if (!e)
883 return NULL;
884
885 e->own_seq_nr = rand();
886 esme_inc_seq_nr(e);
887 osmo_wqueue_init(&e->wqueue, 10);
888
889 return e;
890}
891
Harald Weltef1033cc2012-11-08 16:14:37 +0100892/* callback for already-accepted new TCP socket */
893static int link_accept_cb(struct smsc *smsc, int fd,
894 struct sockaddr_storage *s, socklen_t s_len)
895{
Max366a3402022-08-01 23:01:24 +0700896 struct smpp_esme *esme = talloc_zero(smsc, struct smpp_esme);
Holger Hans Peter Freyther1b624ba2013-07-14 08:59:32 +0200897 if (!esme) {
898 close(fd);
Harald Weltef1033cc2012-11-08 16:14:37 +0100899 return -ENOMEM;
Holger Hans Peter Freyther1b624ba2013-07-14 08:59:32 +0200900 }
Harald Weltef1033cc2012-11-08 16:14:37 +0100901
Max366a3402022-08-01 23:01:24 +0700902 esme->esme = esme_alloc(esme);
903 if (!esme->esme) {
904 close(fd);
905 return -ENOMEM;
906 }
907
Pablo Neira Ayuso93ffbd02017-05-04 18:44:22 +0200908 INIT_LLIST_HEAD(&esme->smpp_cmd_list);
Harald Weltee94db492012-11-08 20:11:05 +0100909 smpp_esme_get(esme);
Harald Weltef1033cc2012-11-08 16:14:37 +0100910 esme->smsc = smsc;
Max366a3402022-08-01 23:01:24 +0700911 osmo_fd_setup(&esme->esme->wqueue.bfd, fd, OSMO_FD_READ, osmo_wqueue_bfd_cb, esme, 0);
Holger Hans Peter Freytherc962d452013-07-14 08:58:15 +0200912
Max366a3402022-08-01 23:01:24 +0700913 if (osmo_fd_register(&esme->esme->wqueue.bfd) != 0) {
Holger Hans Peter Freyther1b624ba2013-07-14 08:59:32 +0200914 close(fd);
Holger Hans Peter Freytherc962d452013-07-14 08:58:15 +0200915 talloc_free(esme);
916 return -EIO;
917 }
Harald Weltef1033cc2012-11-08 16:14:37 +0100918
Max366a3402022-08-01 23:01:24 +0700919 esme->esme->wqueue.read_cb = esme_link_read_cb;
920 esme->esme->wqueue.write_cb = esme_link_write_cb;
Harald Weltef1033cc2012-11-08 16:14:37 +0100921
Harald Weltef1033cc2012-11-08 16:14:37 +0100922 llist_add_tail(&esme->list, &smsc->esme_list);
923
924 return 0;
925}
926
927/* callback of listening TCP socket */
928static int smsc_fd_cb(struct osmo_fd *ofd, unsigned int what)
929{
930 int rc;
931 struct sockaddr_storage sa;
932 socklen_t sa_len = sizeof(sa);
933
934 rc = accept(ofd->fd, (struct sockaddr *)&sa, &sa_len);
935 if (rc < 0) {
936 LOGP(DSMPP, LOGL_ERROR, "Accept returns %d (%s)\n",
937 rc, strerror(errno));
938 return rc;
939 }
940 return link_accept_cb(ofd->data, rc, &sa, sa_len);
941}
942
Neels Hofmeyr1b0e5542016-02-24 19:15:39 +0100943/*! \brief allocate and initialize an smsc struct from talloc context ctx. */
944struct smsc *smpp_smsc_alloc_init(void *ctx)
945{
946 struct smsc *smsc = talloc_zero(ctx, struct smsc);
947
948 INIT_LLIST_HEAD(&smsc->esme_list);
949 INIT_LLIST_HEAD(&smsc->acl_list);
950 INIT_LLIST_HEAD(&smsc->route_list);
951
952 smsc->listen_ofd.data = smsc;
953 smsc->listen_ofd.cb = smsc_fd_cb;
954
955 return smsc;
956}
957
958/*! \brief Set the SMPP address and port without binding. */
959int smpp_smsc_conf(struct smsc *smsc, const char *bind_addr, uint16_t port)
960{
Pau Espin Pedrol7e300d82018-04-17 16:09:22 +0200961 smsc->listen_port = port;
962
963 /* Avoid use-after-free if bind_addr == smsc->bind_addr */
964 if (smsc->bind_addr == bind_addr)
965 return 0;
Vadim Yanitskiye0661102021-10-25 00:49:31 +0300966 osmo_talloc_replace_string(smsc, &smsc->bind_addr, bind_addr);
Pau Espin Pedrol7e300d82018-04-17 16:09:22 +0200967
Neels Hofmeyr1b0e5542016-02-24 19:15:39 +0100968 return 0;
969}
970
Max634591e2022-11-21 16:28:48 +0300971/*! /brief Close SMPP connection. */
972static void smpp_smsc_stop(struct smsc *smsc)
973{
974 if (smsc->listen_ofd.fd > 0) {
975 close(smsc->listen_ofd.fd);
976 smsc->listen_ofd.fd = 0;
977 osmo_fd_unregister(&smsc->listen_ofd);
978 }
979}
980
Neels Hofmeyr1b0e5542016-02-24 19:15:39 +0100981/*! \brief Bind to given address and port and accept connections.
982 * \param[in] bind_addr Local IP address, may be NULL for any.
983 * \param[in] port TCP port number, may be 0 for default SMPP (2775).
984 */
985int smpp_smsc_start(struct smsc *smsc, const char *bind_addr, uint16_t port)
Harald Weltef1033cc2012-11-08 16:14:37 +0100986{
987 int rc;
988
Neels Hofmeyr1b0e5542016-02-24 19:15:39 +0100989 LOGP(DSMPP, LOGL_NOTICE, "SMPP at %s %d\n",
Maxbb624162022-10-20 20:09:06 +0300990 bind_addr ? bind_addr : "0.0.0.0", port ? port : SMPP_PORT);
Harald Welte338e3b32012-11-20 22:22:04 +0100991
Harald Weltef1033cc2012-11-08 16:14:37 +0100992 rc = osmo_sock_init_ofd(&smsc->listen_ofd, AF_UNSPEC, SOCK_STREAM,
Maxbb624162022-10-20 20:09:06 +0300993 IPPROTO_TCP, bind_addr, port ? port : SMPP_PORT,
Harald Welte338e3b32012-11-20 22:22:04 +0100994 OSMO_SOCK_F_BIND);
Neels Hofmeyr1b0e5542016-02-24 19:15:39 +0100995 if (rc < 0)
996 return rc;
Harald Welte338e3b32012-11-20 22:22:04 +0100997
Neels Hofmeyr1b0e5542016-02-24 19:15:39 +0100998 /* store new address and port */
Maxbb624162022-10-20 20:09:06 +0300999 rc = smpp_smsc_conf(smsc, bind_addr, port ? port : SMPP_PORT);
Neels Hofmeyr1b0e5542016-02-24 19:15:39 +01001000 if (rc)
1001 smpp_smsc_stop(smsc);
Harald Weltef1033cc2012-11-08 16:14:37 +01001002 return rc;
1003}
Neels Hofmeyr1b0e5542016-02-24 19:15:39 +01001004
1005/*! \brief Change a running connection to a different address/port, and upon
1006 * error switch back to the running configuration. */
1007int smpp_smsc_restart(struct smsc *smsc, const char *bind_addr, uint16_t port)
1008{
1009 int rc;
1010
Max4b1202b2022-07-27 21:56:49 +07001011 smpp_smsc_stop(smsc);
1012
Neels Hofmeyr1b0e5542016-02-24 19:15:39 +01001013 rc = smpp_smsc_start(smsc, bind_addr, port);
1014 if (rc)
1015 /* if there is an error, try to re-bind to the old port */
1016 return smpp_smsc_start(smsc, smsc->bind_addr, smsc->listen_port);
1017 return 0;
1018}