Kannel: Open Source WAP and SMS gateway  svn-r5335
wtp_pdu.c
Go to the documentation of this file.
1 /* ====================================================================
2  * The Kannel Software License, Version 1.0
3  *
4  * Copyright (c) 2001-2018 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 /* wtp_pdu.c - pack and unpack WTP packets
58  *
59  * Generates packing and unpacking code from wtp_pdu.def.
60  *
61  * Richard Braakman
62  */
63 
64 #include "gwlib/gwlib.h"
65 #include "wtp_pdu.h"
66 
68  WTP_PDU *pdu;
69 
70  pdu = gw_malloc(sizeof(*pdu));
71  pdu->type = type;
72  pdu->options = NULL;
73 
74  switch (pdu->type) {
75 #define PDU(name, docstring, fields, is_valid) \
76  case name: {\
77  struct name *p; p = &pdu->u.name; \
78  fields \
79  } break;
80 #define UINT(field, docstring, bits) p->field = 0;
81 #define UINTVAR(field, docstring) p->field = 0;
82 #define OCTSTR(field, docstring, lengthfield) p->field = NULL;
83 #define REST(field, docstring) p->field = NULL;
84 #define TYPE(bits, value)
85 #define RESERVED(bits)
86 #define TPI(confield)
87 #include "wtp_pdu.def"
88 #undef TPI
89 #undef RESERVED
90 #undef TYPE
91 #undef REST
92 #undef OCTSTR
93 #undef UINTVAR
94 #undef UINT
95 #undef PDU
96  default:
97  warning(0, "Cannot create unknown WTP PDU type %d", pdu->type);
98  break;
99  }
100 
101  return pdu;
102 }
103 
105  if (pdu == NULL)
106  return;
107 
108  switch (pdu->type) {
109 #define PDU(name, docstring, fields, is_valid) \
110  case name: {\
111  struct name *p; p = &pdu->u.name; \
112  fields \
113  } break;
114 #define UINT(field, docstring, bits)
115 #define UINTVAR(field, docstring)
116 #define OCTSTR(field, docstring, lengthfield) octstr_destroy(p->field);
117 #define REST(field, docstring) octstr_destroy(p->field);
118 #define TYPE(bits, value)
119 #define RESERVED(bits)
120 #define TPI(confield)
121 #include "wtp_pdu.def"
122 #undef TPI
123 #undef RESERVED
124 #undef TYPE
125 #undef REST
126 #undef OCTSTR
127 #undef UINTVAR
128 #undef UINT
129 #undef PDU
130  default:
131  warning(0, "Cannot destroy unknown WTP PDU type %d", pdu->type);
132  break;
133  }
134 
135  if (pdu->options) {
136  while (gwlist_len(pdu->options)) {
138  }
139  gwlist_destroy(pdu->options, NULL);
140  }
141 
142  gw_free(pdu);
143 }
144 
146  if (p == NULL)
147  return;
148 
149  octstr_destroy(p->data);
150  gw_free(p);
151 }
152 
153 void wtp_pdu_append_tpi(WTP_PDU *pdu, int type, Octstr *data) {
154  WTP_TPI *tpi;
155 
156  tpi = gw_malloc(sizeof(*tpi));
157  tpi->type = type;
158  tpi->data = data;
159  if (pdu->options == NULL)
160  pdu->options = gwlist_create();
161  gwlist_append(pdu->options, tpi);
162 }
163 
164 static long unpack_tpis(Octstr *data, long bitpos, WTP_PDU *pdu) {
165  long length;
166  int type;
167  Octstr *tpidata;
168  int another;
169 
170  do {
171  another = octstr_get_bits(data, bitpos, 1);
172  type = octstr_get_bits(data, bitpos + 1, 4);
173  if (octstr_get_bits(data, bitpos + 5, 1)) {
174  /* Long TPI */
175  length = octstr_get_bits(data, bitpos + 8, 8);
176  bitpos += 16;
177  } else {
178  /* Short TPI */
179  length = octstr_get_bits(data, bitpos + 6, 2);
180  bitpos += 8;
181  }
182  gw_assert(bitpos % 8 == 0);
183  tpidata = octstr_copy(data, bitpos / 8, length);
184  bitpos += 8 * length;
185  wtp_pdu_append_tpi(pdu, type, tpidata);
186  } while (another);
187 
188  return bitpos;
189 }
190 
191 static long pack_tpis(Octstr *data, long bitpos, List *tpis) {
192  long length;
193  WTP_TPI *tpi;
194  int i;
195  int num_tpis;
196 
197  num_tpis = gwlist_len(tpis);
198  for (i = 0; i < num_tpis; i++) {
199  tpi = gwlist_get(tpis, i);
200  length = octstr_len(tpi->data);
201  octstr_set_bits(data, bitpos, 1, i + 1 < num_tpis);
202  octstr_set_bits(data, bitpos + 1, 4, tpi->type);
203  if (length >= 4) {
204  /* Long TPI */
205  octstr_set_bits(data, bitpos + 5, 1, 1);
206  octstr_set_bits(data, bitpos + 8, 8, length);
207  bitpos += 16;
208  } else {
209  /* Short TPI */
210  octstr_set_bits(data, bitpos + 5, 1, 0);
211  octstr_set_bits(data, bitpos + 6, 2, length);
212  bitpos += 8;
213  }
214  gw_assert(bitpos % 8 == 0);
215  octstr_append(data, tpi->data);
216  bitpos += 8 * length;
217  }
218 
219  return bitpos;
220 }
221 
222 static void dump_tpis(List *tpis, int level) {
223  int i;
224  int num_tpis;
225  WTP_TPI *tpi;
226 
227  if (tpis == NULL)
228  return;
229 
230  num_tpis = gwlist_len(tpis);
231  for (i = 0; i < num_tpis; i++) {
232  tpi = gwlist_get(tpis, i);
233  debug("wap.wtp", 0, "%*s TPI type %u:", level, "", tpi->type);
234  octstr_dump(tpi->data, level + 1);
235  }
236 }
237 
238 /* Determine which type of PDU this is, using the TYPE macros in
239  * the definition file. */
240 static int wtp_pdu_type(Octstr *data) {
241  long bitpos;
242  long lastpos = -1;
243  long lastnumbits = -1;
244  long lastval = -1;
245  int thistype;
246 
247  /* This code looks slow, but an optimizing compiler will
248  * reduce it considerably. gcc -O2 will produce a single
249  * call to octstr_get_bits, folllowed by a sequence of
250  * tests on lastval. */
251 
252 /* Only UINT and RESERVED fields may precede the TYPE */
253 #define PDU(name, docstring, fields, is_valid) \
254  bitpos = 0; \
255  thistype = name; \
256  fields
257 #define UINT(field, docstring, bits) bitpos += (bits);
258 #define UINTVAR(field, docstring)
259 #define OCTSTR(field, docstring, lengthfield)
260 #define REST(field, docstring)
261 #define TYPE(bits, value) \
262  if ((bits) != lastnumbits || bitpos != lastpos) { \
263  lastval = octstr_get_bits(data, bitpos, (bits)); \
264  } \
265  if (lastval == (value)) \
266  return thistype; \
267  lastnumbits = (bits); \
268  lastpos = bitpos;
269 #define RESERVED(bits) bitpos += (bits);
270 #define TPI(confield)
271 #include "wtp_pdu.def"
272 #undef TPI
273 #undef RESERVED
274 #undef TYPE
275 #undef REST
276 #undef OCTSTR
277 #undef UINTVAR
278 #undef UINT
279 #undef PDU
280 
281  return -1;
282 }
283 
285  WTP_PDU *pdu = NULL;
286  long bitpos = 0;
287 
288  gw_assert(data != NULL);
289 
290  pdu = gw_malloc(sizeof(*pdu));
291 
292  pdu->type = wtp_pdu_type(data);
293  pdu->options = NULL;
294 
295  switch (pdu->type) {
296 #define PDU(name, docstring, fields, is_valid) \
297  case name: { \
298  struct name *p = &pdu->u.name; \
299  fields \
300  gw_assert(bitpos % 8 == 0); \
301  if (bitpos / 8 != octstr_len(data)) { \
302  warning(0, "Bad length for " #name " PDU, " \
303  "expected %ld", bitpos / 8); \
304  } \
305  if (!(is_valid)) { \
306  warning(0, #name " PDU failed %s", #is_valid); \
307  return NULL; \
308  } \
309  } break;
310 #define UINT(field, docstring, bits) \
311  p->field = octstr_get_bits(data, bitpos, (bits)); \
312  bitpos += (bits);
313 #define UINTVAR(field, docstring) \
314  gw_assert(bitpos % 8 == 0); \
315  p->field = octstr_get_bits(data, bitpos + 1, 7); \
316  while (octstr_get_bits(data, bitpos, 1)) { \
317  bitpos += 8; \
318  p->field <<= 7; \
319  p->field |= octstr_get_bits(data, bitpos + 1, 7); \
320  } \
321  bitpos += 8;
322 #define OCTSTR(field, docstring, lengthfield) \
323  gw_assert(bitpos % 8 == 0); \
324  p->field = octstr_copy(data, bitpos / 8, p->lengthfield); \
325  bitpos += 8 * p->lengthfield;
326 #define REST(field, docstring) \
327  gw_assert(bitpos % 8 == 0); \
328  if (bitpos / 8 <= octstr_len(data)) { \
329  p->field = octstr_copy(data, bitpos / 8, \
330  octstr_len(data) - bitpos / 8); \
331  bitpos = octstr_len(data) * 8; \
332  } else { \
333  p->field = octstr_create(""); \
334  }
335 #define TYPE(bits, value) bitpos += (bits);
336 #define RESERVED(bits) bitpos += (bits);
337 #define TPI(confield) \
338  if (p->confield) { \
339  pdu->options = gwlist_create(); \
340  bitpos = unpack_tpis(data, bitpos, pdu); \
341  }
342 #include "wtp_pdu.def"
343 #undef TPI
344 #undef RESERVED
345 #undef TYPE
346 #undef REST
347 #undef OCTSTR
348 #undef UINTVAR
349 #undef UINT
350 #undef PDU
351  default:
352  warning(0, "WTP PDU with unknown type %d", pdu->type);
353  gw_free(pdu);
354  return NULL;
355  }
356 
357  return pdu;
358 }
359 
360 static void fixup_length_fields(WTP_PDU *pdu) {
361  switch (pdu->type) {
362 #define PDU(name, docstring, fields, is_valid) \
363  case name: { \
364  struct name *p = &pdu->u.name; \
365  fields \
366  } break;
367 #define UINT(field, docstring, bits)
368 #define UINTVAR(field, docstring)
369 #define OCTSTR(field, docstring, lengthfield) \
370  p->lengthfield = octstr_len(p->field);
371 #define REST(field, docstring)
372 #define TYPE(bits, value)
373 #define RESERVED(bits)
374 #define TPI(confield) \
375  p->confield = pdu->options != NULL && gwlist_len(pdu->options) > 0;
376 #include "wtp_pdu.def"
377 #undef TPI
378 #undef RESERVED
379 #undef TYPE
380 #undef REST
381 #undef OCTSTR
382 #undef UINTVAR
383 #undef UINT
384 #undef PDU
385  }
386 }
387 
389  Octstr *data;
390  long bitpos;
391 
392  /* We rely on octstr_set_bits to lengthen our octstr as needed. */
393  data = octstr_create("");
394 
395  fixup_length_fields(pdu);
396 
397  bitpos = 0;
398  switch (pdu->type) {
399 #define PDU(name, docstring, fields, is_valid) \
400  case name: { \
401  struct name *p = &pdu->u.name; \
402  fields \
403  gw_assert(bitpos % 8 == 0); \
404  } break;
405 #define UINT(field, docstring, bits) \
406  octstr_set_bits(data, bitpos, (bits), p->field); \
407  bitpos += (bits);
408 #define UINTVAR(field, docstring) \
409  gw_assert(bitpos % 8 == 0); \
410  octstr_append_uintvar(data, p->field); \
411  bitpos = 8 * octstr_len(data);
412 #define OCTSTR(field, docstring, lengthfield) \
413  gw_assert(bitpos % 8 == 0); \
414  if (p->field != NULL) \
415  octstr_append(data, p->field); \
416  bitpos += 8 * octstr_len(p->field);
417 #define REST(field, docstring) \
418  gw_assert(bitpos % 8 == 0); \
419  if (p->field != NULL) \
420  octstr_append(data, p->field); \
421  bitpos += 8 * octstr_len(p->field);
422 #define TYPE(bits, value) \
423  octstr_set_bits(data, bitpos, (bits), (value)); \
424  bitpos += (bits);
425 #define RESERVED(bits) bitpos += (bits);
426 #define TPI(confield) \
427  if (p->confield) { \
428  bitpos = pack_tpis(data, bitpos, pdu->options); \
429  }
430 #include "wtp_pdu.def"
431 #undef TPI
432 #undef RESERVED
433 #undef TYPE
434 #undef REST
435 #undef OCTSTR
436 #undef UINTVAR
437 #undef UINT
438 #undef PDU
439  default:
440  panic(0, "Packing unknown WTP PDU type %ld", (long) pdu->type);
441  }
442 
443  return data;
444 }
445 
446 void wtp_pdu_dump(WTP_PDU *pdu, int level) {
447  char *dbg = "wap.wtp";
448 
449  switch (pdu->type) {
450 #define PDU(name, docstring, fields, is_valid) \
451  case name: { \
452  struct name *p = &pdu->u.name; \
453  debug(dbg, 0, "%*sWTP %s PDU at %p:", \
454  level, "", #name, (void *)pdu); \
455  fields \
456  } break;
457 #define UINT(field, docstring, bits) \
458  debug(dbg, 0, "%*s %s: %lu", level, "", docstring, p->field);
459 #define UINTVAR(field, docstring) \
460  debug(dbg, 0, "%*s %s: %lu", level, "", docstring, p->field);
461 #define OCTSTR(field, docstring, lengthfield) \
462  debug(dbg, 0, "%*s %s:", level, "", docstring); \
463  octstr_dump(p->field, level + 1);
464 #define REST(field, docstring) \
465  debug(dbg, 0, "%*s %s:", level, "", docstring); \
466  octstr_dump(p->field, level + 1);
467 #define TYPE(bits, value)
468 #define RESERVED(bits)
469 #define TPI(confield) dump_tpis(pdu->options, level);
470 #include "wtp_pdu.def"
471 #undef TPI
472 #undef RESERVED
473 #undef TYPE
474 #undef REST
475 #undef OCTSTR
476 #undef UINTVAR
477 #undef UINT
478 #undef PDU
479  default:
480  debug(dbg, 0, "%*sWTP PDU at %p:", level, "", (void *)pdu);
481  debug(dbg, 0, "%*s unknown type %u", level, "", pdu->type);
482  break;
483  }
484 }
int type
Definition: wtp_pdu.h:84
WTP_PDU * wtp_pdu_create(int type)
Definition: wtp_pdu.c:67
void wtp_pdu_append_tpi(WTP_PDU *pdu, int type, Octstr *data)
Definition: wtp_pdu.c:153
gw_assert(wtls_machine->packet_to_send !=NULL)
void gwlist_append(List *list, void *item)
Definition: list.c:179
List * options
Definition: wtp_pdu.h:85
void octstr_append(Octstr *ostr1, const Octstr *ostr2)
Definition: octstr.c:1504
void wtp_tpi_destroy(WTP_TPI *p)
Definition: wtp_pdu.c:145
long gwlist_len(List *list)
Definition: list.c:166
void * gwlist_get(List *list, long pos)
Definition: list.c:292
void octstr_set_bits(Octstr *ostr, long bitpos, int numbits, unsigned long value)
Definition: octstr.c:1849
int type
Definition: smsc_cimd2.c:215
void wtp_pdu_dump(WTP_PDU *pdu, int level)
Definition: wtp_pdu.c:446
Octstr * data
Definition: wtp_pdu.h:72
#define octstr_copy(ostr, from, len)
Definition: octstr.h:178
static void dump_tpis(List *tpis, int level)
Definition: wtp_pdu.c:222
int type
Definition: wtp_pdu.h:71
static int wtp_pdu_type(Octstr *data)
Definition: wtp_pdu.c:240
long octstr_get_bits(Octstr *ostr, long bitpos, int numbits)
Definition: octstr.c:1803
static long unpack_tpis(Octstr *data, long bitpos, WTP_PDU *pdu)
Definition: wtp_pdu.c:164
static long pack_tpis(Octstr *data, long bitpos, List *tpis)
Definition: wtp_pdu.c:191
static void fixup_length_fields(WTP_PDU *pdu)
Definition: wtp_pdu.c:360
#define octstr_dump(ostr, level,...)
Definition: octstr.h:564
WTP_PDU * wtp_pdu_unpack(Octstr *data)
Definition: wtp_pdu.c:284
void warning(int err, const char *fmt,...)
Definition: log.c:660
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:324
#define octstr_create(cstr)
Definition: octstr.h:125
long octstr_len(const Octstr *ostr)
Definition: octstr.c:342
Definition: octstr.c:118
void * gwlist_consume(List *list)
Definition: list.c:427
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:726
#define panic
Definition: log.h:87
Octstr * wtp_pdu_pack(WTP_PDU *pdu)
Definition: wtp_pdu.c:388
#define gwlist_create()
Definition: list.h:136
void wtp_pdu_destroy(WTP_PDU *pdu)
Definition: wtp_pdu.c:104
Definition: list.c:102
void gwlist_destroy(List *list, gwlist_item_destructor_t *destructor)
Definition: list.c:145
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.