blob: ff6b1f9e5a80118f50c10e425ae8f10339b68fdf [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
44enum emse_bind {
45 ESME_BIND_RX = 0x01,
46 ESME_BIND_TX = 0x02,
47};
48
49
50
51#define INIT_RESP(type, resp, req) { \
52 memset((resp), 0, sizeof(*(resp))); \
53 (resp)->command_length = 0; \
54 (resp)->command_id = type; \
55 (resp)->command_status = ESME_ROK; \
56 (resp)->sequence_number = (req)->sequence_number; \
57}
58
59#define PACK_AND_SEND(esme, ptr) pack_and_send(esme, (ptr)->command_id, ptr)
60static int pack_and_send(struct osmo_esme *esme, uint32_t type, void *ptr)
61{
62 struct msgb *msg = msgb_alloc(4096, "SMPP_Tx");
63 int rc, rlen;
64 if (!msg)
65 return -ENOMEM;
66
67 rc = smpp34_pack(type, msg->tail, msgb_tailroom(msg), &rlen, ptr);
68 if (rc != 0) {
69 LOGP(DSMPP, LOGL_ERROR, "Error during smpp34_pack(): %s\n",
70 smpp34_strerror);
71 msgb_free(msg);
72 return -EINVAL;
73 }
74 msgb_put(msg, rlen);
75
76 return osmo_wqueue_enqueue(&esme->wqueue, msg);
77}
78
79static int smpp_tx_gen_nack(struct osmo_esme *esme, uint32_t seq, uint32_t status)
80{
81 struct generic_nack_t nack;
82
83 nack.command_length = 0;
84 nack.command_id = GENERIC_NACK;
85 nack.sequence_number = seq;
86 nack.command_status = status;
87
88 return PACK_AND_SEND(esme, &nack);
89}
90
91static inline uint32_t smpp_msgb_cmdid(struct msgb *msg)
92{
93 uint8_t *tmp = msgb_data(msg) + 4;
94 return ntohl(*(uint32_t *)tmp);
95}
96
97static inline uint32_t smpp_msgb_seq(struct msgb *msg)
98{
99 uint8_t *tmp = msgb_data(msg);
100 return ntohl(*(uint32_t *)tmp);
101}
102
103
104static int smpp_handle_gen_nack(struct osmo_esme *esme, struct msgb *msg)
105{
106 struct generic_nack_t nack;
107 char buf[SMALL_BUFF];
108 int rc;
109
110 rc = smpp34_unpack(GENERIC_NACK, &nack, msgb_data(msg),
111 msgb_length(msg));
112 if (rc < 0)
113 return rc;
114
115 LOGP(DSMPP, LOGL_ERROR, "%s: GENERIC NACK: %s\n", esme->system_id,
116 str_command_status(nack.command_status, buf));
117
118 return 0;
119}
120
121static int smpp_handle_bind_rx(struct osmo_esme *esme, struct msgb *msg)
122{
123 struct bind_receiver_t bind;
124 struct bind_receiver_resp_t bind_r;
125 int rc;
126
127 rc = smpp34_unpack(BIND_RECEIVER, &bind, msgb_data(msg),
128 msgb_length(msg));
129 if (rc < 0)
130 return rc;
131
132 INIT_RESP(BIND_TRANSMITTER_RESP, &bind_r, &bind);
133
134 LOGP(DSMPP, LOGL_INFO, "%s: BIND Rx from (Version %02x)\n",
135 bind.system_id, bind.interface_version);
136
137 if (bind.interface_version != SMPP_VERSION) {
138 bind_r.command_status = ESME_RSYSERR;
139 goto err;
140 }
141
142 if (esme->bind_flags) {
143 bind_r.command_status = ESME_RALYBND;
144 goto err;
145 }
146
147 esme->smpp_version = bind.interface_version;
148 snprintf(esme->system_id, sizeof(esme->system_id), "%s",
149 bind.system_id);
150 esme->bind_flags = ESME_BIND_RX;
151
152 /* FIXME */
153err:
154 return 0;
155}
156
157static int smpp_handle_bind_tx(struct osmo_esme *esme, struct msgb *msg)
158{
159 struct bind_transmitter_t bind;
160 struct bind_transmitter_resp_t bind_r;
161 struct tlv_t tlv;
162 int rc;
163
164 rc = smpp34_unpack(BIND_TRANSMITTER, &bind, msgb_data(msg),
165 msgb_length(msg));
166 if (rc < 0) {
167 printf("error during unpack: %s\n", smpp34_strerror);
168 return rc;
169 }
170
171 INIT_RESP(BIND_TRANSMITTER_RESP, &bind_r, &bind);
172
173 LOGP(DSMPP, LOGL_INFO, "%s: BIND Tx (Version %02x)\n",
174 bind.system_id, bind.interface_version);
175
176 if (bind.interface_version != SMPP_VERSION) {
177 bind_r.command_status = ESME_RSYSERR;
178 goto err;
179 }
180
181 if (esme->bind_flags) {
182 bind_r.command_status = ESME_RALYBND;
183 goto err;
184 }
185
186 esme->smpp_version = bind.interface_version;
187 snprintf(esme->system_id, sizeof(esme->system_id), "%s", bind.system_id);
188 esme->bind_flags = ESME_BIND_TX;
189
190 /* build response */
191 snprintf((char *)bind_r.system_id, sizeof(bind_r.system_id), "%s",
192 esme->smsc->system_id);
193
194 /* add interface version TLV */
195 tlv.tag = TLVID_sc_interface_version;
196 tlv.length = sizeof(uint8_t);
197 tlv.value.val16 = esme->smpp_version;
198 build_tlv(&bind_r.tlv, &tlv);
199
200err:
201 return PACK_AND_SEND(esme, &bind_r);
202}
203
204static int smpp_handle_bind_trx(struct osmo_esme *esme, struct msgb *msg)
205{
206 struct bind_transceiver_t bind;
207 struct bind_transceiver_resp_t bind_r;
208 int rc;
209
210 rc = smpp34_unpack(BIND_TRANSCEIVER, &bind, msgb_data(msg),
211 msgb_length(msg));
212 if (rc < 0)
213 return rc;
214
215 INIT_RESP(BIND_TRANSMITTER_RESP, &bind_r, &bind);
216
217 LOGP(DSMPP, LOGL_INFO, "%s: BIND Trx (Version %02x)\n",
218 bind.system_id, bind.interface_version);
219
220 if (bind.interface_version != SMPP_VERSION) {
221 bind_r.command_status = ESME_RSYSERR;
222 goto err;
223 }
224
225 if (esme->bind_flags) {
226 bind_r.command_status = ESME_RALYBND;
227 goto err;
228 }
229
230 esme->smpp_version = bind.interface_version;
231 snprintf(esme->system_id, sizeof(esme->system_id), "%s", bind.system_id);
232 esme->bind_flags |= ESME_BIND_TX | ESME_BIND_RX;
233
234 /* FIXME */
235err:
236 return 0;
237}
238
239static int smpp_handle_unbind(struct osmo_esme *esme, struct msgb *msg)
240{
241 struct unbind_t unbind;
242 struct unbind_resp_t unbind_r;
243 int rc;
244
245 rc = smpp34_unpack(UNBIND, &unbind, msgb_data(msg),
246 msgb_length(msg));
247 if (rc < 0)
248 return rc;
249
250 INIT_RESP(UNBIND_RESP, &unbind_r, &unbind);
251
252 LOGP(DSMPP, LOGL_INFO, "%s: UNBIND\n", esme->system_id);
253
254 if (esme->bind_flags == 0) {
255 unbind_r.command_status = ESME_RINVBNDSTS;
256 goto err;
257 }
258
259 esme->bind_flags = 0;
260err:
261 return PACK_AND_SEND(esme, &unbind_r);
262}
263
264
265static int smpp_handle_enq_link(struct osmo_esme *esme, struct msgb *msg)
266{
267 struct enquire_link_t enq;
268 struct enquire_link_resp_t enq_r;
269 int rc;
270
271 rc = smpp34_unpack(ENQUIRE_LINK, &enq, msgb_data(msg),
272 msgb_length(msg));
273 if (rc < 0)
274 return rc;
275
276 LOGP(DSMPP, LOGL_DEBUG, "%s: Enquire Link\n", esme->system_id);
277
278 INIT_RESP(ENQUIRE_LINK_RESP, &enq_r, &enq);
279
280 return PACK_AND_SEND(esme, &enq_r);
281}
282
283static int smpp_handle_submit(struct osmo_esme *esme, struct msgb *msg)
284{
285 struct submit_sm_t submit;
286 struct submit_sm_resp_t submit_r;
287 int rc;
288
289 rc = smpp34_unpack(SUBMIT_SM, &submit, msgb_data(msg),
290 msgb_length(msg));
291 if (rc < 0)
292 return rc;
293
294 INIT_RESP(SUBMIT_SM_RESP, &submit_r, &submit);
295
296 if (!(esme->bind_flags & ESME_BIND_TX)) {
297 submit_r.command_status = ESME_RINVBNDSTS;
298 return PACK_AND_SEND(esme, &submit_r);
299 }
300
301 LOGP(DSMPP, LOGL_INFO, "%s: SUBMIT-SM(%s)\n", esme->system_id,
302 submit.service_type);
303
304 INIT_RESP(SUBMIT_SM_RESP, &submit_r, &submit);
305
306 rc = handle_smpp_submit(esme, &submit, &submit_r);
307 if (rc == 0)
308 return PACK_AND_SEND(esme, &submit_r);
309
310 return rc;
311}
312
313/* one complete SMPP PDU from the ESME has been received */
314static int smpp_pdu_rx(struct osmo_esme *esme, struct msgb *msg)
315{
316 uint32_t cmd_id = smpp_msgb_cmdid(msg);
317 int rc = 0;
318
319 LOGP(DSMPP, LOGL_DEBUG, "%s: smpp_pdu_rx(%s)\n", esme->system_id,
320 osmo_hexdump(msgb_data(msg), msgb_length(msg)));
321
322 switch (cmd_id) {
323 case GENERIC_NACK:
324 rc = smpp_handle_gen_nack(esme, msg);
325 break;
326 case BIND_RECEIVER:
327 rc = smpp_handle_bind_rx(esme, msg);
328 break;
329 case BIND_TRANSMITTER:
330 rc = smpp_handle_bind_tx(esme, msg);
331 break;
332 case BIND_TRANSCEIVER:
333 rc = smpp_handle_bind_trx(esme, msg);
334 break;
335 case UNBIND:
336 rc = smpp_handle_unbind(esme, msg);
337 break;
338 case ENQUIRE_LINK:
339 rc = smpp_handle_enq_link(esme, msg);
340 break;
341 case SUBMIT_SM:
342 rc = smpp_handle_submit(esme, msg);
343 break;
344 case DELIVER_SM:
345 break;
346 case DATA_SM:
347 break;
348 case CANCEL_SM:
349 case QUERY_SM:
350 case REPLACE_SM:
351 case SUBMIT_MULTI:
352 LOGP(DSMPP, LOGL_NOTICE, "%s: Unimplemented PDU Commmand "
353 "0x%08x\n", esme->system_id, cmd_id);
354 break;
355 default:
356 LOGP(DSMPP, LOGL_ERROR, "%s: Unknown PDU Command 0x%08x\n",
357 esme->system_id, cmd_id);
358 rc = smpp_tx_gen_nack(esme, smpp_msgb_seq(msg), ESME_RINVCMDID);
359 break;
360 }
361
362 return rc;
363}
364
365static void esme_destroy(struct osmo_esme *esme)
366{
367 osmo_wqueue_clear(&esme->wqueue);
368 osmo_fd_unregister(&esme->wqueue.bfd);
369 close(esme->wqueue.bfd.fd);
370 llist_del(&esme->list);
371 talloc_free(esme);
372}
373
374/* call-back when per-ESME TCP socket has some data to be read */
375static int esme_link_read_cb(struct osmo_fd *ofd)
376{
377 struct osmo_esme *esme = ofd->data;
378 uint32_t len;
379 uint8_t *lenptr = (uint8_t *) &len;
380 uint8_t *cur;
381 struct msgb *msg;
382 int rdlen;
383 int rc;
384
385 switch (esme->read_state) {
386 case READ_ST_IN_LEN:
387 rdlen = sizeof(uint32_t) - esme->read_idx;
388 rc = read(ofd->fd, lenptr + esme->read_idx, rdlen);
389 if (rc < 0) {
390 LOGP(DSMPP, LOGL_ERROR, "read returned %d\n", rc);
391 } else if (rc == 0) {
392 goto dead_socket;
393 } else
394 esme->read_idx += rc;
395 if (esme->read_idx >= sizeof(uint32_t)) {
396 esme->read_len = ntohl(len);
397 msg = msgb_alloc(esme->read_len, "SMPP Rx");
398 if (!msg)
399 return -ENOMEM;
400 esme->read_msg = msg;
401 cur = msgb_put(msg, sizeof(uint32_t));
402 memcpy(cur, lenptr, sizeof(uint32_t));
403 esme->read_state = READ_ST_IN_MSG;
404 esme->read_idx = sizeof(uint32_t);
405 }
406 break;
407 case READ_ST_IN_MSG:
408 msg = esme->read_msg;
409 rdlen = esme->read_len - esme->read_idx;
410 rc = read(ofd->fd, msg->tail, OSMO_MIN(rdlen, msgb_tailroom(msg)));
411 if (rc < 0) {
412 LOGP(DSMPP, LOGL_ERROR, "read returned %d\n", rc);
413 } else if (rc == 0) {
414 goto dead_socket;
415 } else {
416 esme->read_idx += rc;
417 msgb_put(msg, rc);
418 }
419
420 if (esme->read_idx >= esme->read_len) {
421 rc = smpp_pdu_rx(esme, esme->read_msg);
422 esme->read_msg = NULL;
423 esme->read_idx = 0;
424 esme->read_len = 0;
425 esme->read_state = READ_ST_IN_LEN;
426 }
427 break;
428 }
429
430 return 0;
431dead_socket:
432 msgb_free(esme->read_msg);
433 esme_destroy(esme);
434
435 return 0;
436}
437
438/* call-back of write queue once it wishes to write a message to the socket */
439static void esme_link_write_cb(struct osmo_fd *ofd, struct msgb *msg)
440{
441 struct osmo_esme *esme = ofd->data;
442 int rc;
443
444 rc = write(ofd->fd, msgb_data(msg), msgb_length(msg));
445 if (rc == 0) {
446 esme_destroy(esme);
447 } else if (rc < msgb_length(msg)) {
448 LOGP(DSMPP, LOGL_ERROR, "%s: Short write\n", esme->system_id);
449 return;
450 }
451}
452
453/* callback for already-accepted new TCP socket */
454static int link_accept_cb(struct smsc *smsc, int fd,
455 struct sockaddr_storage *s, socklen_t s_len)
456{
457 struct osmo_esme *esme = talloc_zero(smsc, struct osmo_esme);
458 if (!esme)
459 return -ENOMEM;
460
461 esme->smsc = smsc;
462 osmo_wqueue_init(&esme->wqueue, 10);
463 esme->wqueue.bfd.fd = fd;
464 esme->wqueue.bfd.data = esme;
465 esme->wqueue.bfd.when = BSC_FD_READ;
466 osmo_fd_register(&esme->wqueue.bfd);
467
468 esme->wqueue.read_cb = esme_link_read_cb;
469 esme->wqueue.write_cb = esme_link_write_cb;
470
471 esme->sa_len = OSMO_MIN(sizeof(esme->sa), s_len);
472 memcpy(&esme->sa, s, esme->sa_len);
473
474 llist_add_tail(&esme->list, &smsc->esme_list);
475
476 return 0;
477}
478
479/* callback of listening TCP socket */
480static int smsc_fd_cb(struct osmo_fd *ofd, unsigned int what)
481{
482 int rc;
483 struct sockaddr_storage sa;
484 socklen_t sa_len = sizeof(sa);
485
486 rc = accept(ofd->fd, (struct sockaddr *)&sa, &sa_len);
487 if (rc < 0) {
488 LOGP(DSMPP, LOGL_ERROR, "Accept returns %d (%s)\n",
489 rc, strerror(errno));
490 return rc;
491 }
492 return link_accept_cb(ofd->data, rc, &sa, sa_len);
493}
494
495int smpp_smsc_init(struct smsc *smsc, uint16_t port)
496{
497 int rc;
498
499 INIT_LLIST_HEAD(&smsc->esme_list);
500 smsc->listen_ofd.data = smsc;
501 smsc->listen_ofd.cb = smsc_fd_cb;
502 rc = osmo_sock_init_ofd(&smsc->listen_ofd, AF_UNSPEC, SOCK_STREAM,
503 IPPROTO_TCP, NULL, port, OSMO_SOCK_F_BIND);
504
505 return rc;
506}