Main Page | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

wtp.c

Go to the documentation of this file.
00001 /* ==================================================================== 
00002  * The Kannel Software License, Version 1.0 
00003  * 
00004  * Copyright (c) 2001-2008 Kannel Group  
00005  * Copyright (c) 1998-2001 WapIT Ltd.   
00006  * All rights reserved. 
00007  * 
00008  * Redistribution and use in source and binary forms, with or without 
00009  * modification, are permitted provided that the following conditions 
00010  * are met: 
00011  * 
00012  * 1. Redistributions of source code must retain the above copyright 
00013  *    notice, this list of conditions and the following disclaimer. 
00014  * 
00015  * 2. Redistributions in binary form must reproduce the above copyright 
00016  *    notice, this list of conditions and the following disclaimer in 
00017  *    the documentation and/or other materials provided with the 
00018  *    distribution. 
00019  * 
00020  * 3. The end-user documentation included with the redistribution, 
00021  *    if any, must include the following acknowledgment: 
00022  *       "This product includes software developed by the 
00023  *        Kannel Group (http://www.kannel.org/)." 
00024  *    Alternately, this acknowledgment may appear in the software itself, 
00025  *    if and wherever such third-party acknowledgments normally appear. 
00026  * 
00027  * 4. The names "Kannel" and "Kannel Group" must not be used to 
00028  *    endorse or promote products derived from this software without 
00029  *    prior written permission. For written permission, please  
00030  *    contact org@kannel.org. 
00031  * 
00032  * 5. Products derived from this software may not be called "Kannel", 
00033  *    nor may "Kannel" appear in their name, without prior written 
00034  *    permission of the Kannel Group. 
00035  * 
00036  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 
00037  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
00038  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
00039  * DISCLAIMED.  IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS 
00040  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,  
00041  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  
00042  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR  
00043  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
00044  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE  
00045  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,  
00046  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
00047  * ==================================================================== 
00048  * 
00049  * This software consists of voluntary contributions made by many 
00050  * individuals on behalf of the Kannel Group.  For more information on  
00051  * the Kannel Group, please see <http://www.kannel.org/>. 
00052  * 
00053  * Portions of this software are based upon software originally written at  
00054  * WapIT Ltd., Helsinki, Finland for the Kannel project.  
00055  */ 
00056 
00057 /*
00058  * wtp.c - WTP common functions implementation
00059  *
00060  * Aarno Syvänen
00061  * Lars Wirzenius
00062  */
00063 
00064 #include "wtp.h" 
00065 #include "wap_events.h"
00066 #include "wtp_pdu.h"
00067 
00068 /*****************************************************************************
00069  *
00070  * Prototypes of internal functions:
00071  *
00072  * Parse a datagram event (T-DUnitdata.ind) to create a corresponding
00073  * WTPEvents list object. Also check that the datagram is syntactically
00074  * valid. Return a pointer to the event structure that has been created.
00075  * This will be a RcvError packet if there was a problem unpacking the
00076  * datagram.
00077  */
00078 
00079 static WAPEvent *unpack_wdp_datagram_real(WAPEvent *datagram);
00080 
00081 static int deduce_tid(Octstr *user_data);
00082 static int concatenated_message(Octstr *user_data);
00083 static int truncated_datagram(WAPEvent *event);
00084 static WAPEvent *unpack_invoke(WTP_PDU *pdu, WAPAddrTuple *addr_tuple);
00085 static WAPEvent *unpack_segmented_invoke(WTP_PDU *pdu, WAPAddrTuple *addr_tuple);
00086 static WAPEvent *unpack_result(WTP_PDU *pdu, WAPAddrTuple *addr_tuple);
00087 static WAPEvent *unpack_ack(WTP_PDU *pdu, WAPAddrTuple *addr_tuple);
00088 static WAPEvent *unpack_negative_ack(WTP_PDU *pdu, WAPAddrTuple *addr_tuple);
00089 static WAPEvent *unpack_abort(WTP_PDU *pdu, WAPAddrTuple *addr_tuple);
00090 static WAPEvent *pack_error(WAPEvent *datagram);
00091 
00092 /******************************************************************************
00093  *
00094  * EXTERNAL FUNCTIONS:
00095  *
00096  * Handles a possible concatenated message. Creates a list of wap events.
00097  */
00098 List *wtp_unpack_wdp_datagram(WAPEvent *datagram)
00099 {
00100      List *events = NULL;
00101      WAPEvent *event = NULL;
00102      WAPEvent *subdgram = NULL;
00103      Octstr *data = NULL;
00104      long pdu_len;
00105 
00106      gw_assert(datagram->type == T_DUnitdata_Ind);
00107 
00108      events = gwlist_create();
00109         
00110      if (concatenated_message(datagram->u.T_DUnitdata_Ind.user_data)) {
00111         data = octstr_duplicate(datagram->u.T_DUnitdata_Ind.user_data);
00112         octstr_delete(data, 0, 1);
00113 
00114         while (octstr_len(data) != 0) {
00115 
00116             if (octstr_get_bits(data, 0, 1) == 0) {
00117                 pdu_len = octstr_get_char(data, 0);
00118                 octstr_delete(data, 0, 1);
00119             } else {
00120                 pdu_len = octstr_get_bits(data, 1, 15);
00121                 octstr_delete(data, 0, 2);
00122             }
00123       
00124             subdgram = wap_event_duplicate(datagram);
00125             octstr_destroy(subdgram->u.T_DUnitdata_Ind.user_data);
00126             subdgram->u.T_DUnitdata_Ind.user_data = octstr_copy(data, 0, pdu_len);
00127             wap_event_assert(subdgram);
00128             if ((event = unpack_wdp_datagram_real(subdgram)) != NULL) {
00129                 wap_event_assert(event);
00130                 gwlist_append(events, event);
00131             }
00132             octstr_delete(data, 0, pdu_len);
00133             wap_event_destroy(subdgram);
00134         }
00135 
00136         octstr_destroy(data);
00137 
00138     } else if ((event = unpack_wdp_datagram_real(datagram)) != NULL) { 
00139         wap_event_assert(event);
00140         gwlist_append(events, event);
00141     } else {
00142         warning(0, "WTP: Dropping unhandled datagram data:");
00143         octstr_dump(datagram->u.T_DUnitdata_Ind.user_data, 0, GW_WARNING);
00144     }
00145 
00146     return events;
00147 }
00148 
00149 /*
00150  * Responder set the first bit of the tid field. If we get a packet from the 
00151  * responder, we are the initiator and vice versa.
00152  *
00153  * Return 1, when the event is for responder, 0 when it is for initiator and 
00154  * -1 when error.
00155  */
00156 int wtp_event_is_for_responder(WAPEvent *event)
00157 {
00158 
00159      switch(event->type){
00160           
00161      case RcvInvoke:
00162          return event->u.RcvInvoke.tid < INITIATOR_TID_LIMIT;
00163 
00164      case RcvSegInvoke:
00165         return event->u.RcvSegInvoke.tid < INITIATOR_TID_LIMIT;
00166 
00167      case RcvResult:
00168          return event->u.RcvResult.tid < INITIATOR_TID_LIMIT;
00169 
00170      case RcvAck:
00171         return event->u.RcvAck.tid < INITIATOR_TID_LIMIT;
00172 
00173      case RcvNegativeAck:
00174         return event->u.RcvNegativeAck.tid < INITIATOR_TID_LIMIT;
00175 
00176      case RcvAbort:
00177         return event->u.RcvAbort.tid < INITIATOR_TID_LIMIT;
00178 
00179      case RcvErrorPDU:
00180         return event->u.RcvErrorPDU.tid < INITIATOR_TID_LIMIT;
00181 
00182      default:
00183         error(1, "Received an erroneous PDU corresponding an event");
00184         wap_event_dump(event);
00185         return -1;
00186      }
00187 }
00188 
00189 /*****************************************************************************
00190  *
00191  * INTERNAL FUNCTIONS:
00192  *
00193  * If pdu was truncated, tid cannot be trusted. We ignore this message.
00194  */
00195 static int truncated_datagram(WAPEvent *dgram)
00196 {
00197     gw_assert(dgram->type == T_DUnitdata_Ind);
00198 
00199     if (octstr_len(dgram->u.T_DUnitdata_Ind.user_data) < 3) {
00200         debug("wap.wtp", 0, "A too short PDU received");
00201         wap_event_dump(dgram);
00202         return 1;
00203     } else
00204         return 0;
00205 }
00206 
00207 static WAPEvent *unpack_invoke(WTP_PDU *pdu, WAPAddrTuple *addr_tuple)
00208 {
00209     WAPEvent *event;
00210 
00211     event = wap_event_create(RcvInvoke);
00212     event->u.RcvInvoke.user_data = 
00213         octstr_duplicate(pdu->u.Invoke.user_data);
00214     event->u.RcvInvoke.tcl = pdu->u.Invoke.class;
00215     event->u.RcvInvoke.tid = pdu->u.Invoke.tid;
00216     event->u.RcvInvoke.tid_new = pdu->u.Invoke.tidnew;
00217     event->u.RcvInvoke.rid = pdu->u.Invoke.rid;
00218     event->u.RcvInvoke.up_flag = pdu->u.Invoke.uack;
00219     event->u.RcvInvoke.no_cache_supported = 0;
00220     event->u.RcvInvoke.version = pdu->u.Invoke.version;
00221     event->u.RcvInvoke.gtr = pdu->u.Invoke.gtr;
00222     event->u.RcvInvoke.ttr = pdu->u.Invoke.ttr;
00223     event->u.RcvInvoke.addr_tuple = wap_addr_tuple_duplicate(addr_tuple);
00224 
00225     return event;
00226 }
00227 
00228 static WAPEvent *unpack_segmented_invoke(WTP_PDU *pdu, WAPAddrTuple *addr_tuple)
00229 {
00230     WAPEvent *event;
00231 
00232     event = wap_event_create(RcvSegInvoke);
00233     event->u.RcvSegInvoke.user_data = 
00234         octstr_duplicate(pdu->u.Segmented_invoke.user_data);
00235     event->u.RcvSegInvoke.tid = pdu->u.Segmented_invoke.tid;
00236     event->u.RcvSegInvoke.rid = pdu->u.Segmented_invoke.rid;
00237     event->u.RcvSegInvoke.no_cache_supported = 0;
00238     event->u.RcvSegInvoke.gtr = pdu->u.Segmented_invoke.gtr;
00239     event->u.RcvSegInvoke.ttr = pdu->u.Segmented_invoke.ttr;
00240     event->u.RcvSegInvoke.psn = pdu->u.Segmented_invoke.psn;
00241     event->u.RcvSegInvoke.addr_tuple = wap_addr_tuple_duplicate(addr_tuple);
00242 
00243     return event;
00244 }
00245 
00246 static WAPEvent *unpack_result(WTP_PDU *pdu, WAPAddrTuple *addr_tuple)
00247 {
00248     WAPEvent *event;
00249 
00250     event = wap_event_create(RcvResult);
00251     event->u.RcvResult.user_data = 
00252         octstr_duplicate(pdu->u.Result.user_data);
00253     event->u.RcvResult.tid = pdu->u.Result.tid;
00254     event->u.RcvResult.rid = pdu->u.Result.rid;
00255     event->u.RcvResult.gtr = pdu->u.Result.gtr;
00256     event->u.RcvResult.ttr = pdu->u.Result.ttr;
00257     event->u.RcvResult.addr_tuple = wap_addr_tuple_duplicate(addr_tuple);
00258 
00259     return event;
00260 }
00261 
00262 static WAPEvent *unpack_ack(WTP_PDU *pdu, WAPAddrTuple *addr_tuple)
00263 {
00264     WAPEvent *event;
00265     WTP_TPI *tpi;
00266     int i, num_tpis;
00267 
00268     event = wap_event_create(RcvAck);
00269     event->u.RcvAck.tid = pdu->u.Ack.tid;
00270     event->u.RcvAck.tid_ok = pdu->u.Ack.tidverify;
00271     event->u.RcvAck.rid = pdu->u.Ack.rid;
00272     event->u.RcvAck.addr_tuple = wap_addr_tuple_duplicate(addr_tuple);
00273 
00274     /* Set default to 0 because Ack on 1 piece message has no tpi */
00275     event->u.RcvAck.psn = 0;
00276     num_tpis = gwlist_len(pdu->options);
00277 
00278     for (i = 0; i < num_tpis; i++) {
00279         tpi = gwlist_get(pdu->options, i);
00280         if (tpi->type == TPI_PSN) {
00281             event->u.RcvAck.psn = octstr_get_bits(tpi->data,0,8);
00282             break;
00283         }
00284     }
00285 
00286     return event;
00287 }
00288 
00289 static WAPEvent *unpack_negative_ack(WTP_PDU *pdu, WAPAddrTuple *addr_tuple)
00290 {
00291     WAPEvent *event;
00292 
00293     event = wap_event_create(RcvNegativeAck);
00294     event->u.RcvNegativeAck.tid = pdu->u.Negative_ack.tid;
00295     event->u.RcvNegativeAck.rid = pdu->u.Negative_ack.rid;
00296     event->u.RcvNegativeAck.nmissing = pdu->u.Negative_ack.nmissing;
00297     event->u.RcvNegativeAck.missing = octstr_duplicate(pdu->u.Negative_ack.missing);
00298     event->u.RcvNegativeAck.addr_tuple = wap_addr_tuple_duplicate(addr_tuple);
00299     
00300     return event;
00301 }
00302 
00303 static WAPEvent *unpack_abort(WTP_PDU *pdu, WAPAddrTuple *addr_tuple)
00304 {
00305      WAPEvent *event;
00306 
00307      event = wap_event_create(RcvAbort);
00308      event->u.RcvAbort.tid = pdu->u.Abort.tid;
00309      event->u.RcvAbort.abort_type = pdu->u.Abort.abort_type;
00310      event->u.RcvAbort.abort_reason = pdu->u.Abort.abort_reason;
00311      event->u.RcvAbort.addr_tuple = wap_addr_tuple_duplicate(addr_tuple);
00312 
00313      return event;
00314 }
00315 
00316 static WAPEvent *pack_error(WAPEvent *datagram)
00317 {
00318     WAPEvent *event;
00319 
00320     gw_assert(datagram->type == T_DUnitdata_Ind);
00321 
00322     event = wap_event_create(RcvErrorPDU);
00323     event->u.RcvErrorPDU.tid = deduce_tid(datagram->u.T_DUnitdata_Ind.user_data);
00324     event->u.RcvErrorPDU.addr_tuple = 
00325     wap_addr_tuple_duplicate(datagram->u.T_DUnitdata_Ind.addr_tuple);
00326 
00327     return event;
00328 }
00329 
00330 /*
00331  * Transfers data from fields of a message to fields of WTP event. User data 
00332  * has the host byte order. Updates the log. 
00333  *
00334  * This function does incoming events check nro 4 (checking illegal headers
00335  * WTP 10.2).
00336  *
00337  * Return event, when we have a partially correct message or the message 
00338  * received has illegal header (WTP 10.2 nro 4); NULL, when the message was 
00339  * truncated or unpacking function returned NULL.
00340  */
00341 
00342 WAPEvent *unpack_wdp_datagram_real(WAPEvent *datagram)
00343 {
00344     WTP_PDU *pdu;
00345     WAPEvent *event;
00346     Octstr *data;
00347 
00348     gw_assert(datagram->type == T_DUnitdata_Ind);
00349 
00350     data = datagram->u.T_DUnitdata_Ind.user_data;
00351 
00352     if (truncated_datagram(datagram)) {
00353         warning(0, "WTP: got a truncated datagram, ignoring");
00354         return NULL;
00355     }
00356 
00357     pdu = wtp_pdu_unpack(data);
00358 
00359     /*
00360      * wtp_pdu_unpack returned NULL, we have send here a rcv error event,
00361      * but now we silently drop the packet. Because we can't figure out
00362      * in the pack_error() call if the TID value and hence the direction
00363      * inditation is really for initiator or responder. 
00364      */
00365     if (pdu == NULL) {
00366         error(0, "WTP: cannot unpack pdu, dropping packet.");
00367         return NULL;
00368     }           
00369 
00370     event = NULL;
00371 
00372     switch (pdu->type) {
00373 
00374     case Invoke:
00375         event = unpack_invoke(pdu, datagram->u.T_DUnitdata_Ind.addr_tuple);
00376         /* if an WTP initiator gets invoke, it would be an illegal pdu. */
00377         if (!wtp_event_is_for_responder(event)){
00378             debug("wap.wtp", 0, "WTP: Invoke when initiator. Message was");
00379             wap_event_destroy(event);
00380             event = pack_error(datagram);
00381         }
00382         break;
00383 
00384     case Segmented_invoke:
00385         event = unpack_segmented_invoke(pdu, datagram->u.T_DUnitdata_Ind.addr_tuple);
00386         break;
00387 
00388     case Result:
00389         event = unpack_result(pdu, datagram->u.T_DUnitdata_Ind.addr_tuple);
00390         /* if an WTP responder gets result, it would be an illegal pdu. */
00391         if (wtp_event_is_for_responder(event)){
00392             debug("wap.wtp", 0, "WTP: Result when responder. Message was");
00393             wap_event_destroy(event);
00394             event = pack_error(datagram);
00395         }
00396         break;
00397 
00398     case Ack:
00399         event = unpack_ack(pdu, datagram->u.T_DUnitdata_Ind.addr_tuple);    
00400         break;
00401 
00402     case Negative_ack:
00403         event = unpack_negative_ack(pdu, datagram->u.T_DUnitdata_Ind.addr_tuple);    
00404         break;
00405 
00406     case Abort:
00407         event = unpack_abort(pdu, datagram->u.T_DUnitdata_Ind.addr_tuple);
00408         break;         
00409 
00410     default:
00411         event = pack_error(datagram);
00412         debug("wap.wtp", 0, "WTP: Unhandled PDU type. Message was");
00413             wap_event_dump(datagram);
00414         return event;
00415     }
00416 
00417     wtp_pdu_destroy(pdu);
00418     
00419     wap_event_assert(event);
00420     return event;
00421 }
00422 
00423 /*
00424  * Used for debugging and when wtp unpack does not return a tid. We include
00425  * first bit; it tells does message received belong to the initiator or to the
00426  * responder.
00427  */
00428 
00429 static int deduce_tid(Octstr *user_data)
00430 { 
00431     return octstr_get_bits(user_data, 8, 16);
00432 }
00433 
00434 static int concatenated_message(Octstr *user_data)
00435 {
00436        return octstr_get_char(user_data, 0) == 0x00;
00437 }
00438 
00439 
00440 
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.