Kannel: Open Source WAP and SMS gateway  svn-r5335
wtp.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 /*
58  * wtp.c - WTP common functions implementation
59  *
60  * Aarno Syvänen
61  * Lars Wirzenius
62  */
63 
64 #include "wtp.h"
65 #include "wap_events.h"
66 #include "wtp_pdu.h"
67 
68 /*****************************************************************************
69  *
70  * Prototypes of internal functions:
71  *
72  * Parse a datagram event (T-DUnitdata.ind) to create a corresponding
73  * WTPEvents list object. Also check that the datagram is syntactically
74  * valid. Return a pointer to the event structure that has been created.
75  * This will be a RcvError packet if there was a problem unpacking the
76  * datagram.
77  */
78 
79 static WAPEvent *unpack_wdp_datagram_real(WAPEvent *datagram);
80 
81 static int deduce_tid(Octstr *user_data);
82 static int concatenated_message(Octstr *user_data);
83 static int truncated_datagram(WAPEvent *event);
90 static WAPEvent *pack_error(WAPEvent *datagram);
91 
92 /******************************************************************************
93  *
94  * EXTERNAL FUNCTIONS:
95  *
96  * Handles a possible concatenated message. Creates a list of wap events.
97  */
99 {
100  List *events = NULL;
101  WAPEvent *event = NULL;
102  WAPEvent *subdgram = NULL;
103  Octstr *data = NULL;
104  long pdu_len;
105 
106  gw_assert(datagram->type == T_DUnitdata_Ind);
107 
108  events = gwlist_create();
109 
110  if (concatenated_message(datagram->u.T_DUnitdata_Ind.user_data)) {
111  data = octstr_duplicate(datagram->u.T_DUnitdata_Ind.user_data);
112  octstr_delete(data, 0, 1);
113 
114  while (octstr_len(data) != 0) {
115 
116  if (octstr_get_bits(data, 0, 1) == 0) {
117  pdu_len = octstr_get_char(data, 0);
118  octstr_delete(data, 0, 1);
119  } else {
120  pdu_len = octstr_get_bits(data, 1, 15);
121  octstr_delete(data, 0, 2);
122  }
123 
124  subdgram = wap_event_duplicate(datagram);
125  octstr_destroy(subdgram->u.T_DUnitdata_Ind.user_data);
126  subdgram->u.T_DUnitdata_Ind.user_data = octstr_copy(data, 0, pdu_len);
127  wap_event_assert(subdgram);
128  if ((event = unpack_wdp_datagram_real(subdgram)) != NULL) {
129  wap_event_assert(event);
130  gwlist_append(events, event);
131  }
132  octstr_delete(data, 0, pdu_len);
133  wap_event_destroy(subdgram);
134  }
135 
136  octstr_destroy(data);
137 
138  } else if ((event = unpack_wdp_datagram_real(datagram)) != NULL) {
139  wap_event_assert(event);
140  gwlist_append(events, event);
141  } else {
142  warning(0, "WTP: Dropping unhandled datagram data:");
143  octstr_dump(datagram->u.T_DUnitdata_Ind.user_data, 0, GW_WARNING);
144  }
145 
146  return events;
147 }
148 
149 /*
150  * Responder set the first bit of the tid field. If we get a packet from the
151  * responder, we are the initiator and vice versa.
152  *
153  * Return 1, when the event is for responder, 0 when it is for initiator and
154  * -1 when error.
155  */
157 {
158 
159  switch(event->type){
160 
161  case RcvInvoke:
162  return event->u.RcvInvoke.tid < INITIATOR_TID_LIMIT;
163 
164  case RcvSegInvoke:
165  return event->u.RcvSegInvoke.tid < INITIATOR_TID_LIMIT;
166 
167  case RcvResult:
168  return event->u.RcvResult.tid < INITIATOR_TID_LIMIT;
169 
170  case RcvAck:
171  return event->u.RcvAck.tid < INITIATOR_TID_LIMIT;
172 
173  case RcvNegativeAck:
174  return event->u.RcvNegativeAck.tid < INITIATOR_TID_LIMIT;
175 
176  case RcvAbort:
177  return event->u.RcvAbort.tid < INITIATOR_TID_LIMIT;
178 
179  case RcvErrorPDU:
180  return event->u.RcvErrorPDU.tid < INITIATOR_TID_LIMIT;
181 
182  default:
183  error(1, "Received an erroneous PDU corresponding an event");
184  wap_event_dump(event);
185  return -1;
186  }
187 }
188 
189 /*****************************************************************************
190  *
191  * INTERNAL FUNCTIONS:
192  *
193  * If pdu was truncated, tid cannot be trusted. We ignore this message.
194  */
195 static int truncated_datagram(WAPEvent *dgram)
196 {
197  gw_assert(dgram->type == T_DUnitdata_Ind);
198 
199  if (octstr_len(dgram->u.T_DUnitdata_Ind.user_data) < 3) {
200  debug("wap.wtp", 0, "A too short PDU received");
201  wap_event_dump(dgram);
202  return 1;
203  } else
204  return 0;
205 }
206 
208 {
209  WAPEvent *event;
210 
211  event = wap_event_create(RcvInvoke);
212  event->u.RcvInvoke.user_data =
213  octstr_duplicate(pdu->u.Invoke.user_data);
214  event->u.RcvInvoke.tcl = pdu->u.Invoke.class;
215  event->u.RcvInvoke.tid = pdu->u.Invoke.tid;
216  event->u.RcvInvoke.tid_new = pdu->u.Invoke.tidnew;
217  event->u.RcvInvoke.rid = pdu->u.Invoke.rid;
218  event->u.RcvInvoke.up_flag = pdu->u.Invoke.uack;
219  event->u.RcvInvoke.no_cache_supported = 0;
220  event->u.RcvInvoke.version = pdu->u.Invoke.version;
221  event->u.RcvInvoke.gtr = pdu->u.Invoke.gtr;
222  event->u.RcvInvoke.ttr = pdu->u.Invoke.ttr;
223  event->u.RcvInvoke.addr_tuple = wap_addr_tuple_duplicate(addr_tuple);
224 
225  return event;
226 }
227 
229 {
230  WAPEvent *event;
231 
232  event = wap_event_create(RcvSegInvoke);
233  event->u.RcvSegInvoke.user_data =
234  octstr_duplicate(pdu->u.Segmented_invoke.user_data);
235  event->u.RcvSegInvoke.tid = pdu->u.Segmented_invoke.tid;
236  event->u.RcvSegInvoke.rid = pdu->u.Segmented_invoke.rid;
237  event->u.RcvSegInvoke.no_cache_supported = 0;
238  event->u.RcvSegInvoke.gtr = pdu->u.Segmented_invoke.gtr;
239  event->u.RcvSegInvoke.ttr = pdu->u.Segmented_invoke.ttr;
240  event->u.RcvSegInvoke.psn = pdu->u.Segmented_invoke.psn;
241  event->u.RcvSegInvoke.addr_tuple = wap_addr_tuple_duplicate(addr_tuple);
242 
243  return event;
244 }
245 
247 {
248  WAPEvent *event;
249 
250  event = wap_event_create(RcvResult);
251  event->u.RcvResult.user_data =
252  octstr_duplicate(pdu->u.Result.user_data);
253  event->u.RcvResult.tid = pdu->u.Result.tid;
254  event->u.RcvResult.rid = pdu->u.Result.rid;
255  event->u.RcvResult.gtr = pdu->u.Result.gtr;
256  event->u.RcvResult.ttr = pdu->u.Result.ttr;
257  event->u.RcvResult.addr_tuple = wap_addr_tuple_duplicate(addr_tuple);
258 
259  return event;
260 }
261 
263 {
264  WAPEvent *event;
265  WTP_TPI *tpi;
266  int i, num_tpis;
267 
268  event = wap_event_create(RcvAck);
269  event->u.RcvAck.tid = pdu->u.Ack.tid;
270  event->u.RcvAck.tid_ok = pdu->u.Ack.tidverify;
271  event->u.RcvAck.rid = pdu->u.Ack.rid;
272  event->u.RcvAck.addr_tuple = wap_addr_tuple_duplicate(addr_tuple);
273 
274  /* Set default to 0 because Ack on 1 piece message has no tpi */
275  event->u.RcvAck.psn = 0;
276  num_tpis = gwlist_len(pdu->options);
277 
278  for (i = 0; i < num_tpis; i++) {
279  tpi = gwlist_get(pdu->options, i);
280  if (tpi->type == TPI_PSN) {
281  event->u.RcvAck.psn = octstr_get_bits(tpi->data,0,8);
282  break;
283  }
284  }
285 
286  return event;
287 }
288 
290 {
291  WAPEvent *event;
292 
293  event = wap_event_create(RcvNegativeAck);
294  event->u.RcvNegativeAck.tid = pdu->u.Negative_ack.tid;
295  event->u.RcvNegativeAck.rid = pdu->u.Negative_ack.rid;
296  event->u.RcvNegativeAck.nmissing = pdu->u.Negative_ack.nmissing;
297  event->u.RcvNegativeAck.missing = octstr_duplicate(pdu->u.Negative_ack.missing);
298  event->u.RcvNegativeAck.addr_tuple = wap_addr_tuple_duplicate(addr_tuple);
299 
300  return event;
301 }
302 
304 {
305  WAPEvent *event;
306 
307  event = wap_event_create(RcvAbort);
308  event->u.RcvAbort.tid = pdu->u.Abort.tid;
309  event->u.RcvAbort.abort_type = pdu->u.Abort.abort_type;
310  event->u.RcvAbort.abort_reason = pdu->u.Abort.abort_reason;
311  event->u.RcvAbort.addr_tuple = wap_addr_tuple_duplicate(addr_tuple);
312 
313  return event;
314 }
315 
316 static WAPEvent *pack_error(WAPEvent *datagram)
317 {
318  WAPEvent *event;
319 
320  gw_assert(datagram->type == T_DUnitdata_Ind);
321 
322  event = wap_event_create(RcvErrorPDU);
323  event->u.RcvErrorPDU.tid = deduce_tid(datagram->u.T_DUnitdata_Ind.user_data);
324  event->u.RcvErrorPDU.addr_tuple =
325  wap_addr_tuple_duplicate(datagram->u.T_DUnitdata_Ind.addr_tuple);
326 
327  return event;
328 }
329 
330 /*
331  * Transfers data from fields of a message to fields of WTP event. User data
332  * has the host byte order. Updates the log.
333  *
334  * This function does incoming events check nro 4 (checking illegal headers
335  * WTP 10.2).
336  *
337  * Return event, when we have a partially correct message or the message
338  * received has illegal header (WTP 10.2 nro 4); NULL, when the message was
339  * truncated or unpacking function returned NULL.
340  */
341 
343 {
344  WTP_PDU *pdu;
345  WAPEvent *event;
346  Octstr *data;
347 
348  gw_assert(datagram->type == T_DUnitdata_Ind);
349 
350  data = datagram->u.T_DUnitdata_Ind.user_data;
351 
352  if (truncated_datagram(datagram)) {
353  warning(0, "WTP: got a truncated datagram, ignoring");
354  return NULL;
355  }
356 
357  pdu = wtp_pdu_unpack(data);
358 
359  /*
360  * wtp_pdu_unpack returned NULL, we have send here a rcv error event,
361  * but now we silently drop the packet. Because we can't figure out
362  * in the pack_error() call if the TID value and hence the direction
363  * inditation is really for initiator or responder.
364  */
365  if (pdu == NULL) {
366  error(0, "WTP: cannot unpack pdu, dropping packet.");
367  return NULL;
368  }
369 
370  event = NULL;
371 
372  switch (pdu->type) {
373 
374  case Invoke:
375  event = unpack_invoke(pdu, datagram->u.T_DUnitdata_Ind.addr_tuple);
376  /* if an WTP initiator gets invoke, it would be an illegal pdu. */
377  if (!wtp_event_is_for_responder(event)){
378  debug("wap.wtp", 0, "WTP: Invoke when initiator. Message was");
379  wap_event_destroy(event);
380  event = pack_error(datagram);
381  }
382  break;
383 
384  case Segmented_invoke:
385  event = unpack_segmented_invoke(pdu, datagram->u.T_DUnitdata_Ind.addr_tuple);
386  break;
387 
388  case Result:
389  event = unpack_result(pdu, datagram->u.T_DUnitdata_Ind.addr_tuple);
390  /* if an WTP responder gets result, it would be an illegal pdu. */
391  if (wtp_event_is_for_responder(event)){
392  debug("wap.wtp", 0, "WTP: Result when responder. Message was");
393  wap_event_destroy(event);
394  event = pack_error(datagram);
395  }
396  break;
397 
398  case Ack:
399  event = unpack_ack(pdu, datagram->u.T_DUnitdata_Ind.addr_tuple);
400  break;
401 
402  case Negative_ack:
403  event = unpack_negative_ack(pdu, datagram->u.T_DUnitdata_Ind.addr_tuple);
404  break;
405 
406  case Abort:
407  event = unpack_abort(pdu, datagram->u.T_DUnitdata_Ind.addr_tuple);
408  break;
409 
410  default:
411  event = pack_error(datagram);
412  debug("wap.wtp", 0, "WTP: Unhandled PDU type. Message was");
413  wap_event_dump(datagram);
414  return event;
415  }
416 
417  wtp_pdu_destroy(pdu);
418 
419  wap_event_assert(event);
420  return event;
421 }
422 
423 /*
424  * Used for debugging and when wtp unpack does not return a tid. We include
425  * first bit; it tells does message received belong to the initiator or to the
426  * responder.
427  */
428 
429 static int deduce_tid(Octstr *user_data)
430 {
431  return octstr_get_bits(user_data, 8, 16);
432 }
433 
434 static int concatenated_message(Octstr *user_data)
435 {
436  return octstr_get_char(user_data, 0) == 0x00;
437 }
438 
439 
440 
void error(int err, const char *fmt,...)
Definition: log.c:648
int type
Definition: wtp_pdu.h:84
List * wtp_unpack_wdp_datagram(WAPEvent *datagram)
Definition: wtp.c:98
static WAPEvent * unpack_segmented_invoke(WTP_PDU *pdu, WAPAddrTuple *addr_tuple)
Definition: wtp.c:228
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
long gwlist_len(List *list)
Definition: list.c:166
static int concatenated_message(Octstr *user_data)
Definition: wtp.c:434
Definition: wtp.h:174
void * gwlist_get(List *list, long pos)
Definition: list.c:292
#define INITIATOR_TID_LIMIT
Definition: wtp.h:183
Octstr * data
Definition: wtp_pdu.h:72
#define octstr_copy(ostr, from, len)
Definition: octstr.h:178
void wap_event_dump(WAPEvent *event)
Definition: wap_events.c:181
WAPAddrTuple * wap_addr_tuple_duplicate(WAPAddrTuple *tuple)
Definition: wap_addr.c:125
static int deduce_tid(Octstr *user_data)
Definition: wtp.c:429
static WAPEvent * pack_error(WAPEvent *datagram)
Definition: wtp.c:316
int type
Definition: wtp_pdu.h:71
long octstr_get_bits(Octstr *ostr, long bitpos, int numbits)
Definition: octstr.c:1803
void wap_event_assert(WAPEvent *event)
Definition: wap_events.c:220
static WAPEvent * unpack_invoke(WTP_PDU *pdu, WAPAddrTuple *addr_tuple)
Definition: wtp.c:207
void octstr_delete(Octstr *ostr1, long pos, long len)
Definition: octstr.c:1527
static WAPEvent * unpack_wdp_datagram_real(WAPEvent *datagram)
Definition: wtp.c:342
union wtp_pdu::@107 u
Definition: log.h:69
int wtp_event_is_for_responder(WAPEvent *event)
Definition: wtp.c:156
#define octstr_duplicate(ostr)
Definition: octstr.h:187
static WAPEvent * unpack_ack(WTP_PDU *pdu, WAPAddrTuple *addr_tuple)
Definition: wtp.c:262
#define octstr_dump(ostr, level,...)
Definition: octstr.h:564
WTP_PDU * wtp_pdu_unpack(Octstr *data)
Definition: wtp_pdu.c:284
#define wap_event_create(type)
Definition: wap_events.h:107
void warning(int err, const char *fmt,...)
Definition: log.c:660
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:324
WAPEvent * wap_event_duplicate(WAPEvent *event)
Definition: wap_events.c:135
long octstr_len(const Octstr *ostr)
Definition: octstr.c:342
Definition: octstr.c:118
static WAPEvent * unpack_abort(WTP_PDU *pdu, WAPAddrTuple *addr_tuple)
Definition: wtp.c:303
static WAPEvent * unpack_negative_ack(WTP_PDU *pdu, WAPAddrTuple *addr_tuple)
Definition: wtp.c:289
static int truncated_datagram(WAPEvent *event)
Definition: wtp.c:195
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:726
WAPEventName type
Definition: wap_events.h:88
#define gwlist_create()
Definition: list.h:136
void wtp_pdu_destroy(WTP_PDU *pdu)
Definition: wtp_pdu.c:104
union WAPEvent::@87 u
int octstr_get_char(const Octstr *ostr, long pos)
Definition: octstr.c:406
Definition: list.c:102
alert u SEC_Terminate_Req addr_tuple
void wap_event_destroy(WAPEvent *event)
Definition: wap_events.c:102
static WAPEvent * unpack_result(WTP_PDU *pdu, WAPAddrTuple *addr_tuple)
Definition: wtp.c:246
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.