1 /* ====================================================================
2 * The Kannel Software License, Version 1.0
3 *
4 * Copyright (c) 2001-2014 Kannel Group
5 * Copyright (c) 1998-2001 WapIT Ltd.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
18 * distribution.
19 *
20 * 3. The end-user documentation included with the redistribution,
21 * if any, must include the following acknowledgment:
22 * "This product includes software developed by the
23 * Kannel Group (http://www.kannel.org/)."
24 * Alternately, this acknowledgment may appear in the software itself,
25 * if and wherever such third-party acknowledgments normally appear.
26 *
27 * 4. The names "Kannel" and "Kannel Group" must not be used to
28 * endorse or promote products derived from this software without
29 * prior written permission. For written permission, please
30 * contact org@kannel.org.
31 *
32 * 5. Products derived from this software may not be called "Kannel",
33 * nor may "Kannel" appear in their name, without prior written
34 * permission of the Kannel Group.
35 *
36 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39 * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
40 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
41 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
42 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
43 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
44 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
45 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
46 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47 * ====================================================================
48 *
49 * This software consists of voluntary contributions made by many
50 * individuals on behalf of the Kannel Group. For more information on
51 * the Kannel Group, please see <http://www.kannel.org/>.
52 *
53 * Portions of this software are based upon software originally written at
54 * WapIT Ltd., Helsinki, Finland for the Kannel project.
55 */
56
57 /*
58 * smpp_pdu.c - parse and generate SMPP PDUs
59 *
60 * Lars Wirzenius
61 * Alexander Malysh <amalysh@kannel.org>:
62 * Extended optional parameters implementation.
63 */
64
65
66 #include <string.h>
67 #include "smpp_pdu.h"
68
69 #define MIN_SMPP_PDU_LEN (4*4)
70 /* old value was (1024). We need more because message_payload can be up to 64K octets*/
71 #define MAX_SMPP_PDU_LEN (7424)
72 /* we use ; in the middle because ; is split char in smsc-id and can't be in the smsc-id */
73 #define DEFAULT_SMSC_ID "def;ault"
74
75 struct smpp_tlv {
76 Octstr *name;
77 long tag;
78 long length;
79 enum { SMPP_TLV_OCTETS = 0, SMPP_TLV_NULTERMINATED = 1, SMPP_TLV_INTEGER = 2 } type;
80 };
81
82 /* Dict(smsc_id, Dict(tag, tlv)) */
83 static Dict *tlvs_by_tag;
84 /* Dict(smsc_id, Dict(tag_name, tlv)) */
85 static Dict *tlvs_by_name;
86 static List *tlvs;
87 static int initialized;
88
89
smpp_tlv_destroy(struct smpp_tlv * tlv)90 static void smpp_tlv_destroy(struct smpp_tlv *tlv)
91 {
92 if (tlv == NULL)
93 return;
94 octstr_destroy(tlv->name);
95 gw_free(tlv);
96 }
97
smpp_tlv_get_by_name(Octstr * smsc_id,Octstr * name)98 static struct smpp_tlv *smpp_tlv_get_by_name(Octstr *smsc_id, Octstr *name)
99 {
100 struct smpp_tlv *res = NULL;
101 Dict *tmp_dict;
102
103 if (tlvs_by_name == NULL || name == NULL)
104 return NULL;
105
106 if (smsc_id != NULL) {
107 tmp_dict = dict_get(tlvs_by_name, smsc_id);
108 if (tmp_dict != NULL)
109 res = dict_get(tmp_dict, name);
110 }
111 if (res == NULL) {
112 /* try default smsc_id */
113 smsc_id = octstr_imm(DEFAULT_SMSC_ID);
114 tmp_dict = dict_get(tlvs_by_name, smsc_id);
115 if (tmp_dict != NULL)
116 res = dict_get(tmp_dict, name);
117 }
118 return res;
119 }
120
smpp_tlv_get_by_tag(Octstr * smsc_id,long tag)121 static struct smpp_tlv *smpp_tlv_get_by_tag(Octstr *smsc_id, long tag)
122 {
123 struct smpp_tlv *res = NULL;
124 Dict *tmp_dict;
125 Octstr *tmp;
126
127 if (tlvs_by_tag == NULL)
128 return NULL;
129
130 tmp = octstr_format("%ld", tag);
131
132 if (smsc_id != NULL) {
133 tmp_dict = dict_get(tlvs_by_tag, smsc_id);
134 if (tmp_dict != NULL)
135 res = dict_get(tmp_dict, tmp);
136 }
137 if (res == NULL) {
138 /* try default smsc_id */
139 smsc_id = octstr_imm(DEFAULT_SMSC_ID);
140 tmp_dict = dict_get(tlvs_by_tag, smsc_id);
141 if (tmp_dict != NULL)
142 res = dict_get(tmp_dict, tmp);
143 }
144
145 octstr_destroy(tmp);
146
147 return res;
148 }
149
smpp_pdu_init(Cfg * cfg)150 int smpp_pdu_init(Cfg *cfg)
151 {
152 CfgGroup *grp;
153 List *l;
154
155 if (initialized)
156 return 0;
157
158 l = cfg_get_multi_group(cfg, octstr_imm("smpp-tlv"));
159 tlvs = gwlist_create();
160 tlvs_by_tag = dict_create(1024, (void(*)(void*))dict_destroy);
161 tlvs_by_name = dict_create(1024, (void(*)(void*))dict_destroy);
162 while (l != NULL && (grp = gwlist_extract_first(l)) != NULL) {
163 struct smpp_tlv *tlv;
164 Octstr *tmp, *smsc_id;
165 List *l2;
166
167 tlv = gw_malloc(sizeof(*tlv));
168 if ((tlv->name = cfg_get(grp, octstr_imm("name"))) == NULL) {
169 error(0, "SMPP: Unable to get name for smpp-tlv.");
170 smpp_tlv_destroy(tlv);
171 goto failed;
172 }
173 if (cfg_get_integer(&tlv->tag, grp, octstr_imm("tag")) == -1) {
174 error(0, "SMPP: Unable to get tag for smpp-tlv.");
175 smpp_tlv_destroy(tlv);
176 goto failed;
177 }
178 if (cfg_get_integer(&tlv->length, grp, octstr_imm("length")) == -1) {
179 error(0, "SMPP: Unable to get length for smpp-tlv.");
180 smpp_tlv_destroy(tlv);
181 goto failed;
182 }
183 if ((tmp = cfg_get(grp, octstr_imm("type"))) == NULL) {
184 error(0, "SMPP: Unable to get type for smpp-tlv.");
185 smpp_tlv_destroy(tlv);
186 goto failed;
187 }
188 if (octstr_str_case_compare(tmp, "octetstring") == 0)
189 tlv->type = SMPP_TLV_OCTETS;
190 else if (octstr_str_case_compare(tmp, "nulterminated") == 0)
191 tlv->type = SMPP_TLV_NULTERMINATED;
192 else if (octstr_str_case_compare(tmp, "integer") == 0)
193 tlv->type = SMPP_TLV_INTEGER;
194 else {
195 error(0, "SMPP: Unknown type for smpp-tlv: `%s'", octstr_get_cstr(tmp));
196 octstr_destroy(tmp);
197 smpp_tlv_destroy(tlv);
198 goto failed;
199 }
200 octstr_destroy(tmp);
201
202 /* put to all TLVs */
203 gwlist_produce(tlvs, tlv);
204
205 smsc_id = cfg_get(grp, octstr_imm("smsc-id"));
206 if (smsc_id != NULL) {
207 l2 = octstr_split(smsc_id, octstr_imm(";"));
208 octstr_destroy(smsc_id);
209 } else {
210 l2 = gwlist_create();
211 gwlist_produce(l2, octstr_create(DEFAULT_SMSC_ID));
212 }
213 while(l2 != NULL && (smsc_id = gwlist_extract_first(l2)) != NULL) {
214 Dict *tmp_dict;
215
216 debug("sms.smpp", 0, "adding smpp-tlv for smsc-id=%s", octstr_get_cstr(smsc_id));
217
218 tmp_dict = dict_get(tlvs_by_name, smsc_id);
219 if (tmp_dict == NULL) {
220 tmp_dict = dict_create(1024, NULL);
221 dict_put(tlvs_by_name, smsc_id, tmp_dict);
222 }
223 /* put into dict */
224 if (!dict_put_once(tmp_dict, tlv->name, tlv)) {
225 error(0, "SMPP: Double TLV name %s found.", octstr_get_cstr(tlv->name));
226 octstr_destroy(smsc_id);
227 goto failed;
228 }
229
230 tmp_dict = dict_get(tlvs_by_tag, smsc_id);
231 if (tmp_dict == NULL) {
232 tmp_dict = dict_create(1024, NULL);
233 dict_put(tlvs_by_tag, smsc_id, tmp_dict);
234 }
235 tmp = octstr_format("%ld", tlv->tag);
236 if (!dict_put_once(tmp_dict, tmp, tlv)) {
237 error(0, "SMPP: Double TLV tag %s found.", octstr_get_cstr(tmp));
238 gwlist_destroy(l2, octstr_destroy_item);
239 octstr_destroy(tmp);
240 octstr_destroy(smsc_id);
241 goto failed;
242 }
243 octstr_destroy(tmp);
244 octstr_destroy(smsc_id);
245 }
246 gwlist_destroy(l2, octstr_destroy_item);
247 }
248 gwlist_destroy(l, NULL);
249
250 initialized = 1;
251 return 0;
252
253 failed:
254 gwlist_destroy(tlvs, (void(*)(void*))smpp_tlv_destroy);
255 dict_destroy(tlvs_by_tag);
256 dict_destroy(tlvs_by_name);
257 return -1;
258 }
259
260
smpp_pdu_shutdown(void)261 int smpp_pdu_shutdown(void)
262 {
263 if (initialized == 0)
264 return 0;
265
266 initialized = 0;
267 gwlist_destroy(tlvs, (void(*)(void*))smpp_tlv_destroy);
268 tlvs = NULL;
269 dict_destroy(tlvs_by_tag);
270 dict_destroy(tlvs_by_name);
271 tlvs_by_tag = tlvs_by_name = NULL;
272
273 return 0;
274 }
275
276
decode_integer(Octstr * os,long pos,int octets)277 static long decode_integer(Octstr *os, long pos, int octets)
278 {
279 unsigned long u;
280 int i;
281
282 if (octstr_len(os) < pos + octets)
283 return -1;
284
285 u = 0;
286 for (i = 0; i < octets; ++i)
287 u = (u << 8) | octstr_get_char(os, pos + i);
288
289 return u;
290 }
291
292
append_encoded_integer(Octstr * os,unsigned long u,long octets)293 static void append_encoded_integer(Octstr *os, unsigned long u, long octets)
294 {
295 long i;
296
297 for (i = 0; i < octets; ++i)
298 octstr_append_char(os, (u >> ((octets - i - 1) * 8)) & 0xFF);
299 }
300
301
copy_until_nul(const char * field_name,Octstr * os,long * pos,long max_octets,Octstr ** data)302 static int copy_until_nul(const char *field_name, Octstr *os, long *pos, long max_octets, Octstr **data)
303 {
304 long nul;
305
306 *data = NULL;
307
308 nul = octstr_search_char(os, '\0', *pos);
309 if (nul == -1) {
310 warning(0, "SMPP: PDU NULL terminated string (%s) has no NULL.", field_name);
311 return -1;
312 }
313 if (*pos + max_octets < nul) {
314 error(0, "SMPP: PDU NULL terminated string (%s) longer than allowed.", field_name);
315 return -1;
316 }
317 *data = (nul - *pos > 0) ? octstr_copy(os, *pos, nul - *pos) : NULL;
318 *pos = nul + 1;
319 return 0;
320 }
321
322
smpp_pdu_create(unsigned long type,unsigned long seq_no)323 SMPP_PDU *smpp_pdu_create(unsigned long type, unsigned long seq_no)
324 {
325 SMPP_PDU *pdu;
326
327 pdu = gw_malloc(sizeof(*pdu));
328 pdu->type = type;
329
330 switch (type) {
331 #define OPTIONAL_BEGIN
332 #define TLV_INTEGER(name, octets) p->name = -1;
333 #define TLV_NULTERMINATED(name, max_len) p->name = NULL;
334 #define TLV_OCTETS(name, min_len, max_len) p->name = NULL;
335 #define OPTIONAL_END p->tlv = dict_create(1024, octstr_destroy_item);
336 #define INTEGER(name, octets) p->name = 0;
337 #define NULTERMINATED(name, max_octets) p->name = NULL;
338 #define OCTETS(name, field_giving_octetst) p->name = NULL;
339 #define PDU(name, id, fields) \
340 case id: { \
341 struct name *p = &pdu->u.name; \
342 pdu->type_name = #name; \
343 fields \
344 p->command_id = type; \
345 p->sequence_number = seq_no; \
346 } break;
347 #include "smpp_pdu.def"
348 default:
349 error(0, "Unknown SMPP_PDU type, internal error.");
350 gw_free(pdu);
351 return NULL;
352 }
353
354 return pdu;
355 }
356
smpp_pdu_destroy(SMPP_PDU * pdu)357 void smpp_pdu_destroy(SMPP_PDU *pdu)
358 {
359 if (pdu == NULL)
360 return;
361
362 switch (pdu->type) {
363 #define OPTIONAL_BEGIN
364 #define TLV_INTEGER(name, octets) p->name = -1;
365 #define TLV_NULTERMINATED(name, max_octets) octstr_destroy(p->name);
366 #define TLV_OCTETS(name, min_len, max_len) octstr_destroy(p->name);
367 #define OPTIONAL_END dict_destroy(p->tlv);
368 #define INTEGER(name, octets) p->name = 0; /* Make sure "p" is used */
369 #define NULTERMINATED(name, max_octets) octstr_destroy(p->name);
370 #define OCTETS(name, field_giving_octets) octstr_destroy(p->name);
371 #define PDU(name, id, fields) \
372 case id: { struct name *p = &pdu->u.name; fields } break;
373 #include "smpp_pdu.def"
374 default:
375 error(0, "Unknown SMPP_PDU type, internal error while destroying.");
376 }
377 gw_free(pdu);
378 }
379
380
smpp_pdu_pack(Octstr * smsc_id,SMPP_PDU * pdu)381 Octstr *smpp_pdu_pack(Octstr *smsc_id, SMPP_PDU *pdu)
382 {
383 Octstr *os;
384 Octstr *temp;
385
386 os = octstr_create("");
387
388 gw_assert(pdu != NULL);
389
390 /*
391 * Fix lengths of octet string fields.
392 */
393 switch (pdu->type) {
394 #define OPTIONAL_BEGIN
395 #define TLV_INTEGER(name, octets)
396 #define TLV_NULTERMINATED(name, max_len)
397 #define TLV_OCTETS(name, min_len, max_len)
398 #define OPTIONAL_END
399 #define INTEGER(name, octets) p = *(&p);
400 #define NULTERMINATED(name, max_octets) p = *(&p);
401 #define OCTETS(name, field_giving_octets) \
402 p->field_giving_octets = octstr_len(p->name);
403 #define PDU(name, id, fields) \
404 case id: { struct name *p = &pdu->u.name; fields } break;
405 #include "smpp_pdu.def"
406 default:
407 error(0, "Unknown SMPP_PDU type, internal error while packing.");
408 }
409
410 switch (pdu->type) {
411 #define TL(name, octets) \
412 append_encoded_integer(os, SMPP_##name, 2); \
413 append_encoded_integer(os, octets, 2);
414 #define OPTIONAL_BEGIN
415 #define TLV_INTEGER(name, octets) \
416 if (p->name >= 0) { \
417 TL(name, octets); \
418 INTEGER(name, octets) \
419 }
420 #define TLV_NULTERMINATED(name, max_len) \
421 if (p->name != NULL) { \
422 TL(name, (octstr_len(p->name) > max_len ? max_len : octstr_len(p->name) + 1)); \
423 NULTERMINATED(name, max_len) \
424 }
425 #define TLV_OCTETS(name, min_len, max_len) \
426 if (p->name != NULL) { \
427 unsigned long len = octstr_len(p->name); \
428 if (len > max_len || len < min_len) { \
429 error(0, "SMPP: Optional field (%s) with invalid length (%ld) (should be %d - %d) dropped.", \
430 #name, len, min_len, max_len);\
431 } else { \
432 TL(name, len); \
433 octstr_append(os, p->name); \
434 } \
435 }
436 #define OPTIONAL_END \
437 if (p->tlv != NULL) { \
438 Octstr *key; \
439 List *keys; \
440 struct smpp_tlv *tlv; \
441 keys = dict_keys(p->tlv); \
442 while(keys != NULL && (key = gwlist_extract_first(keys)) != NULL) { \
443 tlv = smpp_tlv_get_by_name(smsc_id, key); \
444 if (tlv == NULL) { \
445 error(0, "SMPP: Unknown TLV `%s', don't send.", octstr_get_cstr(key)); \
446 octstr_destroy(key); \
447 continue; \
448 } \
449 switch(tlv->type) { \
450 case SMPP_TLV_INTEGER: { \
451 long val = atol(octstr_get_cstr(dict_get(p->tlv, key))); \
452 append_encoded_integer(os, tlv->tag, 2); \
453 append_encoded_integer(os, tlv->length, 2); \
454 append_encoded_integer(os, val, tlv->length); \
455 break; \
456 } \
457 case SMPP_TLV_OCTETS: \
458 case SMPP_TLV_NULTERMINATED: { \
459 Octstr *val = dict_get(p->tlv, key); \
460 unsigned long len = octstr_len(val); \
461 if (len > tlv->length) { \
462 error(0, "SMPP: Optional field (%s) with invalid length (%ld) (should be %ld) dropped.", \
463 octstr_get_cstr(key), len, tlv->length);\
464 octstr_destroy(key); \
465 continue; \
466 } \
467 append_encoded_integer(os, tlv->tag, 2); \
468 if (tlv->type == SMPP_TLV_NULTERMINATED) \
469 append_encoded_integer(os, len + 1, 2); \
470 else \
471 append_encoded_integer(os, len, 2); \
472 octstr_append(os, val); \
473 if (tlv->type == SMPP_TLV_NULTERMINATED) \
474 octstr_append_char(os, '\0'); \
475 break; \
476 } \
477 default: \
478 panic(0, "SMPP: Internal error, unknown configured TLV type %d.", tlv->type); \
479 break; \
480 } \
481 octstr_destroy(key); \
482 } \
483 gwlist_destroy(keys, octstr_destroy_item); \
484 }
485 #define INTEGER(name, octets) \
486 append_encoded_integer(os, p->name, octets);
487 #define NULTERMINATED(name, max_octets) \
488 if (p->name != NULL) { \
489 if (octstr_len(p->name) >= max_octets) { \
490 warning(0, "SMPP: PDU element <%s> too long " \
491 "(length is %ld, should be %d)", \
492 #name, octstr_len(p->name), max_octets-1); \
493 temp = octstr_copy(p->name, 0, max_octets-1); \
494 } else \
495 temp = octstr_duplicate(p->name); \
496 octstr_append(os, temp); \
497 octstr_destroy(temp); \
498 } \
499 octstr_append_char(os, '\0');
500 #define OCTETS(name, field_giving_octets) \
501 if (p->name) octstr_append(os, p->name);
502 #define PDU(name, id, fields) \
503 case id: { struct name *p = &pdu->u.name; fields } break;
504 #include "smpp_pdu.def"
505 default:
506 error(0, "Unknown SMPP_PDU type 0x%08lx, internal error while packing.", pdu->type);
507 break;
508 }
509
510 temp = octstr_create("");
511 append_encoded_integer(temp, octstr_len(os) + 4, 4);
512 octstr_insert(os, temp, 0);
513 octstr_destroy(temp);
514
515 return os;
516 }
517
518
smpp_pdu_unpack(Octstr * smsc_id,Octstr * data_without_len)519 SMPP_PDU *smpp_pdu_unpack(Octstr *smsc_id, Octstr *data_without_len)
520 {
521 SMPP_PDU *pdu;
522 unsigned long type;
523 long len, pos;
524
525 len = octstr_len(data_without_len);
526
527 if (len < 4) {
528 error(0, "SMPP: PDU was too short (%ld bytes).",
529 octstr_len(data_without_len));
530 return NULL;
531 }
532
533 /* get the PDU type */
534 if ((type = decode_integer(data_without_len, 0, 4)) == -1)
535 return NULL;
536
537 /* create a coresponding representation structure */
538 pdu = smpp_pdu_create(type, 0);
539 if (pdu == NULL)
540 return NULL;
541
542 pos = 0;
543
544 switch (type) {
545 #define OPTIONAL_BEGIN \
546 { /* Read optional parameters */ \
547 while (pos + 4 <= len) { \
548 struct smpp_tlv *tlv; \
549 unsigned long opt_tag, opt_len; \
550 opt_tag = decode_integer(data_without_len, pos, 2); pos += 2; \
551 debug("sms.smpp", 0, "Optional parameter tag (0x%04lx)", opt_tag); \
552 opt_len = decode_integer(data_without_len, pos, 2); pos += 2; \
553 debug("sms.smpp", 0, "Optional parameter length read as %ld", opt_len); \
554 /* check configured TLVs */ \
555 tlv = smpp_tlv_get_by_tag(smsc_id, opt_tag); \
556 if (tlv != NULL) debug("sms.smpp", 0, "Found configured optional parameter `%s'", octstr_get_cstr(tlv->name));
557 #define TLV_INTEGER(mname, octets) \
558 if (SMPP_##mname == opt_tag) { \
559 /* check length */ \
560 if (opt_len > octets) { \
561 error(0, "SMPP: Optional field (%s) with invalid length (%ld) dropped.", #mname, opt_len); \
562 pos += opt_len; \
563 continue; \
564 } \
565 INTEGER(mname, opt_len); \
566 if (tlv != NULL) dict_put(p->tlv, tlv->name, octstr_format("%ld", p->mname)); \
567 } else
568 #define TLV_NULTERMINATED(mname, max_len) \
569 if (SMPP_##mname == opt_tag) { \
570 /* check length */ \
571 if (opt_len > max_len || pos+opt_len > len) { \
572 error(0, "SMPP: Optional field (%s) with invalid length (%ld) dropped.", #mname, opt_len); \
573 pos += opt_len; \
574 continue; \
575 } \
576 copy_until_nul(#mname, data_without_len, &pos, opt_len, &p->mname); \
577 if (tlv != NULL) dict_put(p->tlv, tlv->name, octstr_duplicate(p->mname)); \
578 } else
579 #define TLV_OCTETS(mname, min_len, max_len) \
580 if (SMPP_##mname == opt_tag) { \
581 /* check length */ \
582 if (opt_len < min_len || opt_len > max_len || pos + opt_len > len) { \
583 error(0, "SMPP: Optional field (%s) with invalid length (%ld) (should be %d - %d) dropped.", \
584 #mname, opt_len, min_len, max_len); \
585 pos += opt_len; \
586 continue; \
587 } \
588 p->mname = octstr_copy(data_without_len, pos, opt_len); \
589 pos += opt_len; \
590 if (tlv != NULL) dict_put(p->tlv, tlv->name, octstr_duplicate(p->mname)); \
591 } else
592 #define OPTIONAL_END \
593 { \
594 Octstr *val = NULL; \
595 if (tlv != NULL) { \
596 /* found configured tlv */ \
597 /* check length */ \
598 if (opt_len > tlv->length) { \
599 error(0, "SMPP: Optional field (%s) with invalid length (%ld) (should be %ld) dropped.", \
600 octstr_get_cstr(tlv->name), opt_len, tlv->length); \
601 pos += opt_len; \
602 continue; \
603 } \
604 switch (tlv->type) { \
605 case SMPP_TLV_INTEGER: { \
606 long val_i; \
607 if ((val_i = decode_integer(data_without_len, pos, opt_len)) == -1) \
608 goto err; \
609 val = octstr_format("%ld", val_i); \
610 dict_put(p->tlv, tlv->name, val); \
611 pos += opt_len; \
612 break; \
613 } \
614 case SMPP_TLV_OCTETS: { \
615 val = octstr_copy(data_without_len, pos, opt_len); \
616 dict_put(p->tlv, tlv->name, val); \
617 pos += opt_len; \
618 break; \
619 } \
620 case SMPP_TLV_NULTERMINATED: { \
621 if (copy_until_nul(octstr_get_cstr(tlv->name), data_without_len, &pos, opt_len, &val) == 0) \
622 dict_put(p->tlv, tlv->name, val); \
623 break; \
624 } \
625 default: \
626 panic(0, "SMPP: Internal error, unknown configured TLV type %d.", tlv->type); \
627 break; \
628 } \
629 } else { \
630 val = octstr_copy(data_without_len, pos, opt_len); \
631 if (val) \
632 octstr_binary_to_hex(val, 0); \
633 else \
634 val = octstr_create(""); \
635 warning(0, "SMPP: Unknown TLV(0x%04lx,0x%04lx,%s) for PDU type (%s) received!", \
636 opt_tag, opt_len, octstr_get_cstr(val), pdu->type_name); \
637 octstr_destroy(val); \
638 pos += opt_len; \
639 } \
640 } \
641 } \
642 }
643 #define INTEGER(name, octets) \
644 if ((p->name = decode_integer(data_without_len, pos, octets)) == -1) \
645 goto err; \
646 pos += octets;
647 #define NULTERMINATED(name, max_octets) \
648 /* just warn about errors but not fail */ \
649 copy_until_nul(#name, data_without_len, &pos, max_octets, &p->name);
650 #define OCTETS(name, field_giving_octets) \
651 p->name = octstr_copy(data_without_len, pos, \
652 p->field_giving_octets); \
653 if (p->field_giving_octets != (unsigned long) octstr_len(p->name)) { \
654 error(0, "smpp_pdu: error while unpacking '" #name "', " \
655 "len is %ld but should have been %ld, dropping.", \
656 octstr_len(p->name), p->field_giving_octets); \
657 goto err; \
658 } else { \
659 pos += p->field_giving_octets; \
660 }
661 #define PDU(name, id, fields) \
662 case id: { struct name *p = &pdu->u.name; fields } break;
663 #include "smpp_pdu.def"
664 default:
665 error(0, "Unknown SMPP_PDU type 0x%08lx, internal error while unpacking.", type);
666 break;
667 }
668
669 return pdu;
670
671 err:
672 smpp_pdu_destroy(pdu);
673 octstr_dump(data_without_len, 0);
674 return NULL;
675 }
676
677
smpp_pdu_dump(Octstr * smsc_id,SMPP_PDU * pdu)678 void smpp_pdu_dump(Octstr *smsc_id, SMPP_PDU *pdu)
679 {
680 debug("sms.smpp", 0, "SMPP PDU %p dump:", (void *) pdu);
681 debug("sms.smpp", 0, " type_name: %s", pdu->type_name);
682 switch (pdu->type) {
683 #define OPTIONAL_BEGIN
684 #define TLV_INTEGER(name, max_len) \
685 if (p->name != -1) { \
686 INTEGER(name, max_len) \
687 }
688 #define TLV_NULTERMINATED(name, max_len) \
689 if (p->name != NULL) { \
690 NULTERMINATED(name, max_len) \
691 }
692 #define TLV_OCTETS(name, min_len, max_len) \
693 if (p->name != NULL) { \
694 OCTETS(name, max_len) \
695 }
696 #define OPTIONAL_END \
697 if (p->tlv != NULL) { \
698 List *keys; \
699 Octstr *key; \
700 struct smpp_tlv *tlv; \
701 keys = dict_keys(p->tlv); \
702 while(keys != NULL && (key = gwlist_extract_first(keys)) != NULL) { \
703 tlv = smpp_tlv_get_by_name(smsc_id, key); \
704 if (tlv != NULL) { \
705 octstr_dump_short(dict_get(p->tlv, key), 2, octstr_get_cstr(key)); \
706 } \
707 octstr_destroy(key); \
708 } \
709 gwlist_destroy(keys, octstr_destroy_item); \
710 }
711 #define INTEGER(name, octets) \
712 debug("sms.smpp", 0, " %s: %lu = 0x%08lx", #name, p->name, p->name);
713 #define NULTERMINATED(name, max_octets) \
714 octstr_dump_short(p->name, 2, #name);
715 #define OCTETS(name, field_giving_octets) \
716 octstr_dump_short(p->name, 2, #name);
717 #define PDU(name, id, fields) \
718 case id: { struct name *p = &pdu->u.name; fields } break;
719 #include "smpp_pdu.def"
720 default:
721 error(0, "Unknown SMPP_PDU type, internal error.");
722 break;
723 }
724 debug("sms.smpp", 0, "SMPP PDU dump ends.");
725 }
726
727
smpp_pdu_read_len(Connection * conn)728 long smpp_pdu_read_len(Connection *conn)
729 {
730 Octstr *os;
731 unsigned char buf[4]; /* The length is 4 octets. */
732 long len;
733
734 os = conn_read_fixed(conn, sizeof(buf));
735 if (os == NULL)
736 return 0;
737 octstr_get_many_chars((char*) buf, os, 0, sizeof(buf));
738 octstr_destroy(os);
739 len = decode_network_long(buf);
740 if (len < MIN_SMPP_PDU_LEN) {
741 error(0, "SMPP: PDU length was too small (%ld, minimum is %ld).",
742 len, (long) MIN_SMPP_PDU_LEN);
743 return -1;
744 }
745 if (len > MAX_SMPP_PDU_LEN) {
746 error(0, "SMPP: PDU length was too large (%ld, maximum is %ld).",
747 len, (long) MAX_SMPP_PDU_LEN);
748 return -1;
749 }
750 return len;
751 }
752
753
smpp_pdu_read_data(Connection * conn,long len)754 Octstr *smpp_pdu_read_data(Connection *conn, long len)
755 {
756 Octstr *os;
757
758 os = conn_read_fixed(conn, len - 4); /* `len' includes itself. */
759 return os;
760 }
761
762
763 /*
764 * Return error string for given error code
765 * NOTE: If you add new error strings here please use
766 * error strings from SMPP spec. and please keep
767 * error codes in switch statement sorted by error
768 * code ID.
769 */
smpp_error_to_string(enum SMPP_ERROR_MESSAGES error)770 const char *smpp_error_to_string(enum SMPP_ERROR_MESSAGES error)
771 {
772 switch (error) {
773 case SMPP_ESME_ROK:
774 return "OK";
775 case SMPP_ESME_RINVMSGLEN:
776 return "Message Length is invalid";
777 case SMPP_ESME_RINVCMDLEN:
778 return "Command Length is invalid";
779 case SMPP_ESME_RINVCMDID:
780 return "Invalid Command ID";
781 case SMPP_ESME_RINVBNDSTS:
782 return "Incorrect BIND Status for given command";
783 case SMPP_ESME_RALYNBD:
784 return "ESME Already in Bound State";
785 case SMPP_ESME_RINVPRTFLG:
786 return "Invalid Priority Flag";
787 case SMPP_ESME_RINVREGDLVFLG:
788 return "Invalid Registered Delivery Flag";
789 case SMPP_ESME_RSYSERR:
790 return "System Error";
791 case SMPP_ESME_RINVSRCADR:
792 return "Invalid Source Address";
793 case SMPP_ESME_RINVDSTADR:
794 return "Invalid Destination Address";
795 case SMPP_ESME_RBINDFAIL:
796 return "Bind Failed";
797 case SMPP_ESME_RINVPASWD:
798 return "Invalid Password";
799 case SMPP_ESME_RINVSYSID:
800 return "Invalid System ID";
801 case SMPP_ESME_RCANCELFAIL:
802 return "Cancel SM Failed";
803 case SMPP_ESME_RREPLACEFAIL:
804 return "Replace SM Failed";
805 case SMPP_ESME_RMSGQFUL:
806 return "Message Queue Full";
807 case SMPP_ESME_RINVSERTYP:
808 return "Invalid Service Type";
809 case SMPP_ESME_RINVNUMDESTS:
810 return "Invalid number of destinations";
811 case SMPP_ESME_RINVDLNAME:
812 return "Invalid Distribution List Name";
813 case SMPP_ESME_RINVDESTFLAG:
814 return "Destination flag is invalid";
815 case SMPP_ESME_RINVSUBREP:
816 return "Submit w/replace not supported/allowed";
817 case SMPP_ESME_RINVESMCLASS:
818 return "Invalid esm_class field data";
819 case SMPP_ESME_RCNTSUBDL:
820 return "Cannot Submit to Distribution List";
821 case SMPP_ESME_RSUBMITFAIL:
822 return "Submit failed";
823 case SMPP_ESME_RINVSRCTON:
824 return "Invalid Source address TON";
825 case SMPP_ESME_RINVSRCNPI:
826 return "Invalid Source address NPI";
827 case SMPP_ESME_RINVDSTTON:
828 return "Invalid Destination address TON";
829 case SMPP_ESME_RINVDSTNPI:
830 return "Invalid Destination address NPI";
831 case SMPP_ESME_RINVSYSTYP:
832 return "Invalid system_type field";
833 case SMPP_ESME_RINVREPFLAG:
834 return "Invalid replace_if_present flag";
835 case SMPP_ESME_RINVNUMMSGS:
836 return "Invalid number of messages";
837 case SMPP_ESME_RTHROTTLED:
838 return "Throttling error";
839 case SMPP_ESME_RINVSCHED:
840 return "Invalid Scheduled Delivery Time";
841 case SMPP_ESME_RINVEXPIRY:
842 return "Invalid message validity period";
843 case SMPP_ESME_RINVDFTMSGID:
844 return "Predefined Message ID is Invalid or specific predefined message was not found";
845 case SMPP_ESME_RX_T_APPN:
846 return "ESME Receiver Temporary App Error Code";
847 case SMPP_ESME_RX_P_APPN:
848 return "ESME Receiver Permanent App Error Code";
849 case SMPP_ESME_RX_R_APPN:
850 return "ESME Receiver Reject Message Error Code";
851 case SMPP_ESME_RQUERYFAIL:
852 return "query_sm request failed";
853 case SMPP_ESME_RINVTLVSTREAM:
854 return "Error in optional part of the PDU Body";
855 case SMPP_ESME_RTLVNOTALLWD:
856 return "TLV not allowed";
857 case SMPP_ESME_RINVTLVLEN:
858 return "Invalid Parameter Length";
859 case SMPP_ESME_RMISSINGTLV:
860 return "Expected TLV missing";
861 case SMPP_ESME_RINVTLVVAL:
862 return "Invalid TLV value";
863 case SMPP_ESME_RDELIVERYFAILURE:
864 return "Transaction Delivery Failure";
865 case SMPP_ESME_RUNKNOWNERR:
866 return "Unknown Error";
867 case SMPP_ESME_RSERTYPUNAUTH:
868 return "ESME Not authorized to use specified service_type";
869 case SMPP_ESME_RPROHIBITED:
870 return "ESME Prohibited from using specified operation";
871 case SMPP_ESME_RSERTYPUNAVAIL:
872 return "Specified service_type is unavailable";
873 case SMPP_ESME_RSERTYPDENIED:
874 return "Specified service_type is denied";
875 case SMPP_ESME_RINVDCS:
876 return "Invalid Data Coding Scheme";
877 case SMPP_ESME_RINVSRCADDRSUBUNIT:
878 return "Source Address Sub unit is invalid";
879 case SMPP_ESME_RINVDSTADDRSUBUNIT:
880 return "Destination Address Sub unit is invalid";
881 case SMPP_ESME_RINVBCASTFREQINT:
882 return "Broadcast Frequency Interval is invalid";
883 case SMPP_ESME_RINVBCASTALIAS_NAME:
884 return "Broadcast Alias Name is invalid";
885 case SMPP_ESME_RINVBCASTAREAFMT:
886 return "Broadcast Area Format is invalid";
887 case SMPP_ESME_RINVNUMBCAST_AREAS:
888 return "Number of Broadcast Areas is invalid";
889 case SMPP_ESME_RINVBCASTCNTTYPE:
890 return "Broadcast Content Type is invalid";
891 case SMPP_ESME_RINVBCASTMSGCLASS:
892 return "Broadcast Message Class is invalid";
893 case SMPP_ESME_RBCASTFAIL:
894 return "broadcast_sm operation failed";
895 case SMPP_ESME_RBCASTQUERYFAIL:
896 return "broadcast_query_sm operation failed";
897 case SMPP_ESME_RBCASTCANCELFAIL:
898 return "broadcast_cancel_sm operation failed";
899 case SMPP_ESME_RINVBCAST_REP:
900 return "Number of Repeated Broadcasts is invalid";
901 case SMPP_ESME_RINVBCASTSRVGRP:
902 return "Broadcast Service Group is invalid";
903 case SMPP_ESME_RINVBCASTCHANIND:
904 return "Broadcast Channel Indicator is invalid";
905
906 default:
907 /* tell the user that we have a vendor-specific beast here */
908 if (error >= 0x0400 && error <= 0x04FF)
909 return "Vendor-specific error, please refer to your SMPP provider";
910 else
911 return "Unknown/Reserved";
912 }
913 }
914