blob: 8957c8ee5172d2b7f5596677fb405db5f5abc6f4 [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 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18
19
20#include <stdio.h>
21#include <unistd.h>
22#include <string.h>
23#include <stdint.h>
24#include <errno.h>
25
26#include <sys/socket.h>
27#include <netinet/in.h>
28
29#include <smpp34.h>
30#include <smpp34_structs.h>
31#include <smpp34_params.h>
32
33#include <osmocom/core/utils.h>
34#include <osmocom/core/socket.h>
35#include <osmocom/core/msgb.h>
36#include <osmocom/core/logging.h>
37#include <osmocom/core/write_queue.h>
38#include <osmocom/core/talloc.h>
39
40#include "smpp_smsc.h"
41
42#include <openbsc/debug.h>
43
Harald Welte4dbcdad2012-11-08 22:12:45 +010044/*! \brief Ugly wrapper. libsmpp34 should do this itself! */
45#define SMPP34_UNPACK(rc, type, str, data, len) \
46 memset(str, 0, sizeof(*str)); \
47 rc = smpp34_unpack(type, str, data, len)
48
Harald Weltef1033cc2012-11-08 16:14:37 +010049enum emse_bind {
50 ESME_BIND_RX = 0x01,
51 ESME_BIND_TX = 0x02,
52};
53
Harald Weltee94db492012-11-08 20:11:05 +010054/*! \brief increaes the use/reference count */
55void smpp_esme_get(struct osmo_esme *esme)
56{
57 esme->use++;
58}
59
60static void esme_destroy(struct osmo_esme *esme)
61{
62 osmo_wqueue_clear(&esme->wqueue);
63 if (esme->wqueue.bfd.fd >= 0) {
64 osmo_fd_unregister(&esme->wqueue.bfd);
65 close(esme->wqueue.bfd.fd);
66 }
67 llist_del(&esme->list);
68 talloc_free(esme);
69}
70
71/*! \brief decrease the use/reference count, free if it is 0 */
72void smpp_esme_put(struct osmo_esme *esme)
73{
74 esme->use--;
75 if (esme->use <= 0)
76 esme_destroy(esme);
77}
78
Harald Welted4bdee72012-11-08 19:44:08 +010079static struct osmo_esme *
80esme_by_system_id(const struct smsc *smsc, char *system_id)
81{
82 struct osmo_esme *e;
83
84 llist_for_each_entry(e, &smsc->esme_list, list) {
85 if (!strcmp(e->system_id, system_id))
86 return e;
87 }
88 return NULL;
89}
Harald Weltef1033cc2012-11-08 16:14:37 +010090
91
Harald Weltee94db492012-11-08 20:11:05 +010092/*! \brief initialize the libsmpp34 data structure for a response */
Harald Weltef1033cc2012-11-08 16:14:37 +010093#define INIT_RESP(type, resp, req) { \
94 memset((resp), 0, sizeof(*(resp))); \
95 (resp)->command_length = 0; \
96 (resp)->command_id = type; \
97 (resp)->command_status = ESME_ROK; \
98 (resp)->sequence_number = (req)->sequence_number; \
99}
100
Harald Weltee94db492012-11-08 20:11:05 +0100101/*! \brief pack a libsmpp34 data strcutrure and send it to the ESME */
Harald Weltef1033cc2012-11-08 16:14:37 +0100102#define PACK_AND_SEND(esme, ptr) pack_and_send(esme, (ptr)->command_id, ptr)
103static int pack_and_send(struct osmo_esme *esme, uint32_t type, void *ptr)
104{
105 struct msgb *msg = msgb_alloc(4096, "SMPP_Tx");
106 int rc, rlen;
107 if (!msg)
108 return -ENOMEM;
109
110 rc = smpp34_pack(type, msg->tail, msgb_tailroom(msg), &rlen, ptr);
111 if (rc != 0) {
Harald Welte874f9f12012-11-09 13:02:49 +0100112 LOGP(DSMPP, LOGL_ERROR, "[%s] Error during smpp34_pack(): %s\n",
113 esme->system_id, smpp34_strerror);
Harald Weltef1033cc2012-11-08 16:14:37 +0100114 msgb_free(msg);
115 return -EINVAL;
116 }
117 msgb_put(msg, rlen);
118
119 return osmo_wqueue_enqueue(&esme->wqueue, msg);
120}
121
Harald Weltee94db492012-11-08 20:11:05 +0100122/*! \brief transmit a generic NACK to a remote ESME */
Harald Weltef1033cc2012-11-08 16:14:37 +0100123static int smpp_tx_gen_nack(struct osmo_esme *esme, uint32_t seq, uint32_t status)
124{
125 struct generic_nack_t nack;
Harald Welte874f9f12012-11-09 13:02:49 +0100126 char buf[SMALL_BUFF];
Harald Weltef1033cc2012-11-08 16:14:37 +0100127
128 nack.command_length = 0;
129 nack.command_id = GENERIC_NACK;
130 nack.sequence_number = seq;
131 nack.command_status = status;
132
Harald Welte874f9f12012-11-09 13:02:49 +0100133 LOGP(DSMPP, LOGL_ERROR, "[%s] Tx GENERIC NACK: %s\n",
134 esme->system_id, str_command_status(status, buf));
135
Harald Weltef1033cc2012-11-08 16:14:37 +0100136 return PACK_AND_SEND(esme, &nack);
137}
138
Harald Weltee94db492012-11-08 20:11:05 +0100139/*! \brief retrieve SMPP command ID from a msgb */
Harald Weltef1033cc2012-11-08 16:14:37 +0100140static inline uint32_t smpp_msgb_cmdid(struct msgb *msg)
141{
142 uint8_t *tmp = msgb_data(msg) + 4;
143 return ntohl(*(uint32_t *)tmp);
144}
145
Harald Weltee94db492012-11-08 20:11:05 +0100146/*! \brief retrieve SMPP sequence number from a msgb */
Harald Weltef1033cc2012-11-08 16:14:37 +0100147static inline uint32_t smpp_msgb_seq(struct msgb *msg)
148{
149 uint8_t *tmp = msgb_data(msg);
150 return ntohl(*(uint32_t *)tmp);
151}
152
Harald Weltee94db492012-11-08 20:11:05 +0100153/*! \brief handle an incoming SMPP generic NACK */
Harald Weltef1033cc2012-11-08 16:14:37 +0100154static int smpp_handle_gen_nack(struct osmo_esme *esme, struct msgb *msg)
155{
156 struct generic_nack_t nack;
157 char buf[SMALL_BUFF];
158 int rc;
159
Harald Welte4dbcdad2012-11-08 22:12:45 +0100160 SMPP34_UNPACK(rc, GENERIC_NACK, &nack, msgb_data(msg),
161 msgb_length(msg));
Harald Welte874f9f12012-11-09 13:02:49 +0100162 if (rc < 0) {
163 LOGP(DSMPP, LOGL_ERROR, "[%s] Error in smpp34_unpack():%s\n",
164 esme->system_id, smpp34_strerror);
Harald Weltef1033cc2012-11-08 16:14:37 +0100165 return rc;
Harald Welte874f9f12012-11-09 13:02:49 +0100166 }
Harald Weltef1033cc2012-11-08 16:14:37 +0100167
Harald Welte874f9f12012-11-09 13:02:49 +0100168 LOGP(DSMPP, LOGL_ERROR, "[%s] Rx GENERIC NACK: %s\n",
169 esme->system_id, str_command_status(nack.command_status, buf));
Harald Weltef1033cc2012-11-08 16:14:37 +0100170
171 return 0;
172}
173
Harald Weltee94db492012-11-08 20:11:05 +0100174/*! \brief handle an incoming SMPP BIND RECEIVER */
Harald Weltef1033cc2012-11-08 16:14:37 +0100175static int smpp_handle_bind_rx(struct osmo_esme *esme, struct msgb *msg)
176{
177 struct bind_receiver_t bind;
178 struct bind_receiver_resp_t bind_r;
179 int rc;
180
Harald Welte4dbcdad2012-11-08 22:12:45 +0100181 SMPP34_UNPACK(rc, BIND_RECEIVER, &bind, msgb_data(msg),
Harald Weltef1033cc2012-11-08 16:14:37 +0100182 msgb_length(msg));
Harald Welte874f9f12012-11-09 13:02:49 +0100183 if (rc < 0) {
184 LOGP(DSMPP, LOGL_ERROR, "[%s] Error in smpp34_unpack():%s\n",
185 esme->system_id, smpp34_strerror);
Harald Weltef1033cc2012-11-08 16:14:37 +0100186 return rc;
Harald Welte874f9f12012-11-09 13:02:49 +0100187 }
Harald Weltef1033cc2012-11-08 16:14:37 +0100188
189 INIT_RESP(BIND_TRANSMITTER_RESP, &bind_r, &bind);
190
Harald Welte874f9f12012-11-09 13:02:49 +0100191 LOGP(DSMPP, LOGL_INFO, "[%s] Rx BIND Rx from (Version %02x)\n",
Harald Weltef1033cc2012-11-08 16:14:37 +0100192 bind.system_id, bind.interface_version);
193
194 if (bind.interface_version != SMPP_VERSION) {
195 bind_r.command_status = ESME_RSYSERR;
196 goto err;
197 }
198
199 if (esme->bind_flags) {
200 bind_r.command_status = ESME_RALYBND;
201 goto err;
202 }
203
204 esme->smpp_version = bind.interface_version;
205 snprintf(esme->system_id, sizeof(esme->system_id), "%s",
206 bind.system_id);
207 esme->bind_flags = ESME_BIND_RX;
208
209 /* FIXME */
210err:
211 return 0;
212}
213
Harald Weltee94db492012-11-08 20:11:05 +0100214/*! \brief handle an incoming SMPP BIND TRANSMITTER */
Harald Weltef1033cc2012-11-08 16:14:37 +0100215static int smpp_handle_bind_tx(struct osmo_esme *esme, struct msgb *msg)
216{
217 struct bind_transmitter_t bind;
218 struct bind_transmitter_resp_t bind_r;
219 struct tlv_t tlv;
220 int rc;
221
Harald Welte4dbcdad2012-11-08 22:12:45 +0100222 SMPP34_UNPACK(rc, BIND_TRANSMITTER, &bind, msgb_data(msg),
Harald Weltef1033cc2012-11-08 16:14:37 +0100223 msgb_length(msg));
224 if (rc < 0) {
Harald Welte874f9f12012-11-09 13:02:49 +0100225 LOGP(DSMPP, LOGL_ERROR, "[%s] Error in smpp34_unpack():%s\n",
226 esme->system_id, smpp34_strerror);
Harald Weltef1033cc2012-11-08 16:14:37 +0100227 return rc;
228 }
229
230 INIT_RESP(BIND_TRANSMITTER_RESP, &bind_r, &bind);
231
Harald Welte874f9f12012-11-09 13:02:49 +0100232 LOGP(DSMPP, LOGL_INFO, "[%s] Rx BIND Tx (Version %02x)\n",
Harald Weltef1033cc2012-11-08 16:14:37 +0100233 bind.system_id, bind.interface_version);
234
235 if (bind.interface_version != SMPP_VERSION) {
236 bind_r.command_status = ESME_RSYSERR;
237 goto err;
238 }
239
240 if (esme->bind_flags) {
241 bind_r.command_status = ESME_RALYBND;
242 goto err;
243 }
244
245 esme->smpp_version = bind.interface_version;
246 snprintf(esme->system_id, sizeof(esme->system_id), "%s", bind.system_id);
247 esme->bind_flags = ESME_BIND_TX;
248
249 /* build response */
250 snprintf((char *)bind_r.system_id, sizeof(bind_r.system_id), "%s",
251 esme->smsc->system_id);
252
253 /* add interface version TLV */
254 tlv.tag = TLVID_sc_interface_version;
255 tlv.length = sizeof(uint8_t);
256 tlv.value.val16 = esme->smpp_version;
257 build_tlv(&bind_r.tlv, &tlv);
258
259err:
260 return PACK_AND_SEND(esme, &bind_r);
261}
262
Harald Weltee94db492012-11-08 20:11:05 +0100263/*! \brief handle an incoming SMPP BIND TRANSCEIVER */
Harald Weltef1033cc2012-11-08 16:14:37 +0100264static int smpp_handle_bind_trx(struct osmo_esme *esme, struct msgb *msg)
265{
266 struct bind_transceiver_t bind;
267 struct bind_transceiver_resp_t bind_r;
268 int rc;
269
Harald Welte4dbcdad2012-11-08 22:12:45 +0100270 SMPP34_UNPACK(rc, BIND_TRANSCEIVER, &bind, msgb_data(msg),
Harald Weltef1033cc2012-11-08 16:14:37 +0100271 msgb_length(msg));
Harald Welte874f9f12012-11-09 13:02:49 +0100272 if (rc < 0) {
273 LOGP(DSMPP, LOGL_ERROR, "[%s] Error in smpp34_unpack():%s\n",
274 esme->system_id, smpp34_strerror);
Harald Weltef1033cc2012-11-08 16:14:37 +0100275 return rc;
Harald Welte874f9f12012-11-09 13:02:49 +0100276 }
Harald Weltef1033cc2012-11-08 16:14:37 +0100277
278 INIT_RESP(BIND_TRANSMITTER_RESP, &bind_r, &bind);
279
Harald Welte874f9f12012-11-09 13:02:49 +0100280 LOGP(DSMPP, LOGL_INFO, "[%s] Rx BIND Trx (Version %02x)\n",
Harald Weltef1033cc2012-11-08 16:14:37 +0100281 bind.system_id, bind.interface_version);
282
283 if (bind.interface_version != SMPP_VERSION) {
284 bind_r.command_status = ESME_RSYSERR;
285 goto err;
286 }
287
288 if (esme->bind_flags) {
289 bind_r.command_status = ESME_RALYBND;
290 goto err;
291 }
292
293 esme->smpp_version = bind.interface_version;
294 snprintf(esme->system_id, sizeof(esme->system_id), "%s", bind.system_id);
295 esme->bind_flags |= ESME_BIND_TX | ESME_BIND_RX;
296
297 /* FIXME */
298err:
299 return 0;
300}
301
Harald Weltee94db492012-11-08 20:11:05 +0100302/*! \brief handle an incoming SMPP UNBIND */
Harald Weltef1033cc2012-11-08 16:14:37 +0100303static int smpp_handle_unbind(struct osmo_esme *esme, struct msgb *msg)
304{
305 struct unbind_t unbind;
306 struct unbind_resp_t unbind_r;
307 int rc;
308
Harald Welte4dbcdad2012-11-08 22:12:45 +0100309 SMPP34_UNPACK(rc, UNBIND, &unbind, msgb_data(msg),
Harald Weltef1033cc2012-11-08 16:14:37 +0100310 msgb_length(msg));
Harald Welte874f9f12012-11-09 13:02:49 +0100311 if (rc < 0) {
312 LOGP(DSMPP, LOGL_ERROR, "[%s] Error in smpp34_unpack():%s\n",
313 esme->system_id, smpp34_strerror);
Harald Weltef1033cc2012-11-08 16:14:37 +0100314 return rc;
Harald Welte874f9f12012-11-09 13:02:49 +0100315 }
Harald Weltef1033cc2012-11-08 16:14:37 +0100316
317 INIT_RESP(UNBIND_RESP, &unbind_r, &unbind);
318
Harald Welte874f9f12012-11-09 13:02:49 +0100319 LOGP(DSMPP, LOGL_INFO, "[%s] Rx UNBIND\n", esme->system_id);
Harald Weltef1033cc2012-11-08 16:14:37 +0100320
321 if (esme->bind_flags == 0) {
322 unbind_r.command_status = ESME_RINVBNDSTS;
323 goto err;
324 }
325
326 esme->bind_flags = 0;
327err:
328 return PACK_AND_SEND(esme, &unbind_r);
329}
330
Harald Weltee94db492012-11-08 20:11:05 +0100331/*! \brief handle an incoming SMPP ENQUIRE LINK */
Harald Weltef1033cc2012-11-08 16:14:37 +0100332static int smpp_handle_enq_link(struct osmo_esme *esme, struct msgb *msg)
333{
334 struct enquire_link_t enq;
335 struct enquire_link_resp_t enq_r;
336 int rc;
337
Harald Welte4dbcdad2012-11-08 22:12:45 +0100338 SMPP34_UNPACK(rc, ENQUIRE_LINK, &enq, msgb_data(msg),
Harald Weltef1033cc2012-11-08 16:14:37 +0100339 msgb_length(msg));
Harald Welte874f9f12012-11-09 13:02:49 +0100340 if (rc < 0) {
341 LOGP(DSMPP, LOGL_ERROR, "[%s] Error in smpp34_unpack():%s\n",
342 esme->system_id, smpp34_strerror);
Harald Weltef1033cc2012-11-08 16:14:37 +0100343 return rc;
Harald Welte874f9f12012-11-09 13:02:49 +0100344 }
Harald Weltef1033cc2012-11-08 16:14:37 +0100345
Harald Welte874f9f12012-11-09 13:02:49 +0100346 LOGP(DSMPP, LOGL_DEBUG, "[%s] Rx Enquire Link\n", esme->system_id);
Harald Weltef1033cc2012-11-08 16:14:37 +0100347
348 INIT_RESP(ENQUIRE_LINK_RESP, &enq_r, &enq);
349
Harald Welte874f9f12012-11-09 13:02:49 +0100350 LOGP(DSMPP, LOGL_DEBUG, "[%s] Tx Enquire Link Response\n", esme->system_id);
351
Harald Weltef1033cc2012-11-08 16:14:37 +0100352 return PACK_AND_SEND(esme, &enq_r);
353}
354
Harald Weltee94db492012-11-08 20:11:05 +0100355/*! \brief send a SUBMIT-SM RESPONSE to a remote ESME */
Harald Welted4bdee72012-11-08 19:44:08 +0100356int smpp_tx_submit_r(struct osmo_esme *esme, uint32_t sequence_nr,
357 uint32_t command_status, char *msg_id)
358{
359 struct submit_sm_resp_t submit_r;
360
361 memset(&submit_r, 0, sizeof(submit_r));
362 submit_r.command_length = 0;
363 submit_r.command_id = SUBMIT_SM_RESP;
364 submit_r.command_status = command_status;
365 submit_r.sequence_number= sequence_nr;
Harald Welte8a1b0562012-11-09 12:51:44 +0100366 snprintf((char *) submit_r.message_id, sizeof(submit_r.message_id), "%s", msg_id);
Harald Welted4bdee72012-11-08 19:44:08 +0100367
368 return PACK_AND_SEND(esme, &submit_r);
369}
370
Harald Welte8a1b0562012-11-09 12:51:44 +0100371static const struct value_string smpp_avail_strs[] = {
372 { 0, "Available" },
373 { 1, "Denied" },
374 { 2, "Unavailable" },
375 { 0, NULL }
376};
377
378/*! \brief send an ALERT_NOTIFICATION to a remote ESME */
379int smpp_tx_alert(struct osmo_esme *esme, uint8_t ton, uint8_t npi,
380 const char *addr, uint8_t avail_status)
381{
382 struct alert_notification_t alert;
383 struct tlv_t tlv;
384
385 memset(&alert, 0, sizeof(alert));
386 alert.command_length = 0;
387 alert.command_id = ALERT_NOTIFICATION;
388 alert.command_status = ESME_ROK;
389 alert.sequence_number = esme->own_seq_nr++;
390 alert.source_addr_ton = ton;
391 alert.source_addr_npi = npi;
Harald Welte874f9f12012-11-09 13:02:49 +0100392 snprintf((char *)alert.source_addr, sizeof(alert.source_addr), "%s", addr);
Harald Welte8a1b0562012-11-09 12:51:44 +0100393
394 tlv.tag = TLVID_ms_availability_status;
395 tlv.length = sizeof(uint8_t);
396 tlv.value.val08 = avail_status;
397 build_tlv(&alert.tlv, &tlv);
398
399 LOGP(DSMPP, LOGL_DEBUG, "[%s] Tx ALERT_NOTIFICATION (%s/%u/%u): %s\n",
400 esme->system_id, alert.source_addr, alert.source_addr_ton,
401 alert.source_addr_npi,
402 get_value_string(smpp_avail_strs, avail_status));
403
404 return PACK_AND_SEND(esme, &alert);
405}
406
Harald Weltee94db492012-11-08 20:11:05 +0100407/*! \brief handle an incoming SMPP SUBMIT-SM */
Harald Weltef1033cc2012-11-08 16:14:37 +0100408static int smpp_handle_submit(struct osmo_esme *esme, struct msgb *msg)
409{
410 struct submit_sm_t submit;
411 struct submit_sm_resp_t submit_r;
412 int rc;
413
Harald Welte4dbcdad2012-11-08 22:12:45 +0100414 memset(&submit, 0, sizeof(submit));
415 SMPP34_UNPACK(rc, SUBMIT_SM, &submit, msgb_data(msg),
Harald Weltef1033cc2012-11-08 16:14:37 +0100416 msgb_length(msg));
Harald Welte874f9f12012-11-09 13:02:49 +0100417 if (rc < 0) {
418 LOGP(DSMPP, LOGL_ERROR, "[%s] Error in smpp34_unpack():%s\n",
419 esme->system_id, smpp34_strerror);
Harald Weltef1033cc2012-11-08 16:14:37 +0100420 return rc;
Harald Welte874f9f12012-11-09 13:02:49 +0100421 }
Harald Weltef1033cc2012-11-08 16:14:37 +0100422
423 INIT_RESP(SUBMIT_SM_RESP, &submit_r, &submit);
424
425 if (!(esme->bind_flags & ESME_BIND_TX)) {
426 submit_r.command_status = ESME_RINVBNDSTS;
427 return PACK_AND_SEND(esme, &submit_r);
428 }
429
Harald Welte874f9f12012-11-09 13:02:49 +0100430 LOGP(DSMPP, LOGL_INFO, "[%s] Rx SUBMIT-SM (%s/%u/%u)\n",
431 esme->system_id, submit.destination_addr,
432 submit.dest_addr_ton, submit.dest_addr_npi);
Harald Weltef1033cc2012-11-08 16:14:37 +0100433
434 INIT_RESP(SUBMIT_SM_RESP, &submit_r, &submit);
435
436 rc = handle_smpp_submit(esme, &submit, &submit_r);
437 if (rc == 0)
438 return PACK_AND_SEND(esme, &submit_r);
439
440 return rc;
441}
442
Harald Weltee94db492012-11-08 20:11:05 +0100443/*! \brief one complete SMPP PDU from the ESME has been received */
Harald Weltef1033cc2012-11-08 16:14:37 +0100444static int smpp_pdu_rx(struct osmo_esme *esme, struct msgb *msg)
445{
446 uint32_t cmd_id = smpp_msgb_cmdid(msg);
447 int rc = 0;
448
Harald Welte874f9f12012-11-09 13:02:49 +0100449 LOGP(DSMPP, LOGL_DEBUG, "[%s] smpp_pdu_rx(%s)\n", esme->system_id,
Harald Weltef1033cc2012-11-08 16:14:37 +0100450 osmo_hexdump(msgb_data(msg), msgb_length(msg)));
451
452 switch (cmd_id) {
453 case GENERIC_NACK:
454 rc = smpp_handle_gen_nack(esme, msg);
455 break;
456 case BIND_RECEIVER:
457 rc = smpp_handle_bind_rx(esme, msg);
458 break;
459 case BIND_TRANSMITTER:
460 rc = smpp_handle_bind_tx(esme, msg);
461 break;
462 case BIND_TRANSCEIVER:
463 rc = smpp_handle_bind_trx(esme, msg);
464 break;
465 case UNBIND:
466 rc = smpp_handle_unbind(esme, msg);
467 break;
468 case ENQUIRE_LINK:
469 rc = smpp_handle_enq_link(esme, msg);
470 break;
471 case SUBMIT_SM:
472 rc = smpp_handle_submit(esme, msg);
473 break;
474 case DELIVER_SM:
475 break;
476 case DATA_SM:
477 break;
478 case CANCEL_SM:
479 case QUERY_SM:
480 case REPLACE_SM:
481 case SUBMIT_MULTI:
Harald Welte874f9f12012-11-09 13:02:49 +0100482 LOGP(DSMPP, LOGL_NOTICE, "[%s] Unimplemented PDU Commmand "
Harald Weltef1033cc2012-11-08 16:14:37 +0100483 "0x%08x\n", esme->system_id, cmd_id);
484 break;
485 default:
Harald Welte874f9f12012-11-09 13:02:49 +0100486 LOGP(DSMPP, LOGL_ERROR, "[%s] Unknown PDU Command 0x%08x\n",
Harald Weltef1033cc2012-11-08 16:14:37 +0100487 esme->system_id, cmd_id);
488 rc = smpp_tx_gen_nack(esme, smpp_msgb_seq(msg), ESME_RINVCMDID);
489 break;
490 }
491
492 return rc;
493}
494
Harald Weltee94db492012-11-08 20:11:05 +0100495/* !\brief call-back when per-ESME TCP socket has some data to be read */
Harald Weltef1033cc2012-11-08 16:14:37 +0100496static int esme_link_read_cb(struct osmo_fd *ofd)
497{
498 struct osmo_esme *esme = ofd->data;
499 uint32_t len;
500 uint8_t *lenptr = (uint8_t *) &len;
501 uint8_t *cur;
502 struct msgb *msg;
503 int rdlen;
504 int rc;
505
506 switch (esme->read_state) {
507 case READ_ST_IN_LEN:
508 rdlen = sizeof(uint32_t) - esme->read_idx;
509 rc = read(ofd->fd, lenptr + esme->read_idx, rdlen);
510 if (rc < 0) {
Harald Welte874f9f12012-11-09 13:02:49 +0100511 LOGP(DSMPP, LOGL_ERROR, "[%s] read returned %d\n",
512 esme->system_id, rc);
Harald Weltef1033cc2012-11-08 16:14:37 +0100513 } else if (rc == 0) {
514 goto dead_socket;
515 } else
516 esme->read_idx += rc;
517 if (esme->read_idx >= sizeof(uint32_t)) {
518 esme->read_len = ntohl(len);
519 msg = msgb_alloc(esme->read_len, "SMPP Rx");
520 if (!msg)
521 return -ENOMEM;
522 esme->read_msg = msg;
523 cur = msgb_put(msg, sizeof(uint32_t));
524 memcpy(cur, lenptr, sizeof(uint32_t));
525 esme->read_state = READ_ST_IN_MSG;
526 esme->read_idx = sizeof(uint32_t);
527 }
528 break;
529 case READ_ST_IN_MSG:
530 msg = esme->read_msg;
531 rdlen = esme->read_len - esme->read_idx;
532 rc = read(ofd->fd, msg->tail, OSMO_MIN(rdlen, msgb_tailroom(msg)));
533 if (rc < 0) {
Harald Welte874f9f12012-11-09 13:02:49 +0100534 LOGP(DSMPP, LOGL_ERROR, "[%s] read returned %d\n",
535 esme->system_id, rc);
Harald Weltef1033cc2012-11-08 16:14:37 +0100536 } else if (rc == 0) {
537 goto dead_socket;
538 } else {
539 esme->read_idx += rc;
540 msgb_put(msg, rc);
541 }
542
543 if (esme->read_idx >= esme->read_len) {
544 rc = smpp_pdu_rx(esme, esme->read_msg);
545 esme->read_msg = NULL;
546 esme->read_idx = 0;
547 esme->read_len = 0;
548 esme->read_state = READ_ST_IN_LEN;
549 }
550 break;
551 }
552
553 return 0;
554dead_socket:
555 msgb_free(esme->read_msg);
Harald Weltee94db492012-11-08 20:11:05 +0100556 osmo_fd_unregister(&esme->wqueue.bfd);
557 close(esme->wqueue.bfd.fd);
558 esme->wqueue.bfd.fd = -1;
559 smpp_esme_put(esme);
Harald Weltef1033cc2012-11-08 16:14:37 +0100560
561 return 0;
562}
563
564/* call-back of write queue once it wishes to write a message to the socket */
565static void esme_link_write_cb(struct osmo_fd *ofd, struct msgb *msg)
566{
567 struct osmo_esme *esme = ofd->data;
568 int rc;
569
570 rc = write(ofd->fd, msgb_data(msg), msgb_length(msg));
571 if (rc == 0) {
Harald Weltee94db492012-11-08 20:11:05 +0100572 osmo_fd_unregister(&esme->wqueue.bfd);
573 close(esme->wqueue.bfd.fd);
574 esme->wqueue.bfd.fd = -1;
575 smpp_esme_put(esme);
Harald Weltef1033cc2012-11-08 16:14:37 +0100576 } else if (rc < msgb_length(msg)) {
Harald Welte874f9f12012-11-09 13:02:49 +0100577 LOGP(DSMPP, LOGL_ERROR, "[%s] Short write\n", esme->system_id);
Harald Weltef1033cc2012-11-08 16:14:37 +0100578 return;
579 }
580}
581
582/* callback for already-accepted new TCP socket */
583static int link_accept_cb(struct smsc *smsc, int fd,
584 struct sockaddr_storage *s, socklen_t s_len)
585{
586 struct osmo_esme *esme = talloc_zero(smsc, struct osmo_esme);
587 if (!esme)
588 return -ENOMEM;
589
Harald Weltee94db492012-11-08 20:11:05 +0100590 smpp_esme_get(esme);
Harald Welte8a1b0562012-11-09 12:51:44 +0100591 esme->own_seq_nr = rand();
Harald Weltef1033cc2012-11-08 16:14:37 +0100592 esme->smsc = smsc;
593 osmo_wqueue_init(&esme->wqueue, 10);
594 esme->wqueue.bfd.fd = fd;
595 esme->wqueue.bfd.data = esme;
596 esme->wqueue.bfd.when = BSC_FD_READ;
597 osmo_fd_register(&esme->wqueue.bfd);
598
599 esme->wqueue.read_cb = esme_link_read_cb;
600 esme->wqueue.write_cb = esme_link_write_cb;
601
602 esme->sa_len = OSMO_MIN(sizeof(esme->sa), s_len);
603 memcpy(&esme->sa, s, esme->sa_len);
604
605 llist_add_tail(&esme->list, &smsc->esme_list);
606
607 return 0;
608}
609
610/* callback of listening TCP socket */
611static int smsc_fd_cb(struct osmo_fd *ofd, unsigned int what)
612{
613 int rc;
614 struct sockaddr_storage sa;
615 socklen_t sa_len = sizeof(sa);
616
617 rc = accept(ofd->fd, (struct sockaddr *)&sa, &sa_len);
618 if (rc < 0) {
619 LOGP(DSMPP, LOGL_ERROR, "Accept returns %d (%s)\n",
620 rc, strerror(errno));
621 return rc;
622 }
623 return link_accept_cb(ofd->data, rc, &sa, sa_len);
624}
625
Harald Weltee94db492012-11-08 20:11:05 +0100626/*! \brief Initialize the SMSC-side SMPP implementation */
Harald Weltef1033cc2012-11-08 16:14:37 +0100627int smpp_smsc_init(struct smsc *smsc, uint16_t port)
628{
629 int rc;
630
631 INIT_LLIST_HEAD(&smsc->esme_list);
632 smsc->listen_ofd.data = smsc;
633 smsc->listen_ofd.cb = smsc_fd_cb;
634 rc = osmo_sock_init_ofd(&smsc->listen_ofd, AF_UNSPEC, SOCK_STREAM,
635 IPPROTO_TCP, NULL, port, OSMO_SOCK_F_BIND);
636
637 return rc;
638}