00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064 #include "gwlib/gwlib.h"
00065 #include "wtp_pdu.h"
00066
00067 WTP_PDU *wtp_pdu_create(int type) {
00068 WTP_PDU *pdu;
00069
00070 pdu = gw_malloc(sizeof(*pdu));
00071 pdu->type = type;
00072 pdu->options = NULL;
00073
00074 switch (pdu->type) {
00075 #define PDU(name, docstring, fields, is_valid) \
00076 case name: {\
00077 struct name *p; p = &pdu->u.name; \
00078 fields \
00079 } break;
00080 #define UINT(field, docstring, bits) p->field = 0;
00081 #define UINTVAR(field, docstring) p->field = 0;
00082 #define OCTSTR(field, docstring, lengthfield) p->field = NULL;
00083 #define REST(field, docstring) p->field = NULL;
00084 #define TYPE(bits, value)
00085 #define RESERVED(bits)
00086 #define TPI(confield)
00087 #include "wtp_pdu.def"
00088 #undef TPI
00089 #undef RESERVED
00090 #undef TYPE
00091 #undef REST
00092 #undef OCTSTR
00093 #undef UINTVAR
00094 #undef UINT
00095 #undef PDU
00096 default:
00097 warning(0, "Cannot create unknown WTP PDU type %d", pdu->type);
00098 break;
00099 }
00100
00101 return pdu;
00102 }
00103
00104 void wtp_pdu_destroy(WTP_PDU *pdu) {
00105 if (pdu == NULL)
00106 return;
00107
00108 switch (pdu->type) {
00109 #define PDU(name, docstring, fields, is_valid) \
00110 case name: {\
00111 struct name *p; p = &pdu->u.name; \
00112 fields \
00113 } break;
00114 #define UINT(field, docstring, bits)
00115 #define UINTVAR(field, docstring)
00116 #define OCTSTR(field, docstring, lengthfield) octstr_destroy(p->field);
00117 #define REST(field, docstring) octstr_destroy(p->field);
00118 #define TYPE(bits, value)
00119 #define RESERVED(bits)
00120 #define TPI(confield)
00121 #include "wtp_pdu.def"
00122 #undef TPI
00123 #undef RESERVED
00124 #undef TYPE
00125 #undef REST
00126 #undef OCTSTR
00127 #undef UINTVAR
00128 #undef UINT
00129 #undef PDU
00130 default:
00131 warning(0, "Cannot destroy unknown WTP PDU type %d", pdu->type);
00132 break;
00133 }
00134
00135 if (pdu->options) {
00136 while (gwlist_len(pdu->options)) {
00137 wtp_tpi_destroy(gwlist_consume(pdu->options));
00138 }
00139 gwlist_destroy(pdu->options, NULL);
00140 }
00141
00142 gw_free(pdu);
00143 }
00144
00145 void wtp_tpi_destroy(WTP_TPI *p) {
00146 if (p == NULL)
00147 return;
00148
00149 octstr_destroy(p->data);
00150 gw_free(p);
00151 }
00152
00153 void wtp_pdu_append_tpi(WTP_PDU *pdu, int type, Octstr *data) {
00154 WTP_TPI *tpi;
00155
00156 tpi = gw_malloc(sizeof(*tpi));
00157 tpi->type = type;
00158 tpi->data = data;
00159 if (pdu->options == NULL)
00160 pdu->options = gwlist_create();
00161 gwlist_append(pdu->options, tpi);
00162 }
00163
00164 static long unpack_tpis(Octstr *data, long bitpos, WTP_PDU *pdu) {
00165 long length;
00166 int type;
00167 Octstr *tpidata;
00168 int another;
00169
00170 do {
00171 another = octstr_get_bits(data, bitpos, 1);
00172 type = octstr_get_bits(data, bitpos + 1, 4);
00173 if (octstr_get_bits(data, bitpos + 5, 1)) {
00174
00175 length = octstr_get_bits(data, bitpos + 8, 8);
00176 bitpos += 16;
00177 } else {
00178
00179 length = octstr_get_bits(data, bitpos + 6, 2);
00180 bitpos += 8;
00181 }
00182 gw_assert(bitpos % 8 == 0);
00183 tpidata = octstr_copy(data, bitpos / 8, length);
00184 bitpos += 8 * length;
00185 wtp_pdu_append_tpi(pdu, type, tpidata);
00186 } while (another);
00187
00188 return bitpos;
00189 }
00190
00191 static long pack_tpis(Octstr *data, long bitpos, List *tpis) {
00192 long length;
00193 WTP_TPI *tpi;
00194 int i;
00195 int num_tpis;
00196
00197 num_tpis = gwlist_len(tpis);
00198 for (i = 0; i < num_tpis; i++) {
00199 tpi = gwlist_get(tpis, i);
00200 length = octstr_len(tpi->data);
00201 octstr_set_bits(data, bitpos, 1, i + 1 < num_tpis);
00202 octstr_set_bits(data, bitpos + 1, 4, tpi->type);
00203 if (length >= 4) {
00204
00205 octstr_set_bits(data, bitpos + 5, 1, 1);
00206 octstr_set_bits(data, bitpos + 8, 8, length);
00207 bitpos += 16;
00208 } else {
00209
00210 octstr_set_bits(data, bitpos + 5, 1, 0);
00211 octstr_set_bits(data, bitpos + 6, 2, length);
00212 bitpos += 8;
00213 }
00214 gw_assert(bitpos % 8 == 0);
00215 octstr_append(data, tpi->data);
00216 bitpos += 8 * length;
00217 }
00218
00219 return bitpos;
00220 }
00221
00222 static void dump_tpis(List *tpis, int level) {
00223 int i;
00224 int num_tpis;
00225 WTP_TPI *tpi;
00226
00227 if (tpis == NULL)
00228 return;
00229
00230 num_tpis = gwlist_len(tpis);
00231 for (i = 0; i < num_tpis; i++) {
00232 tpi = gwlist_get(tpis, i);
00233 debug("wap.wtp", 0, "%*s TPI type %u:", level, "", tpi->type);
00234 octstr_dump(tpi->data, level + 1);
00235 }
00236 }
00237
00238
00239
00240 static int wtp_pdu_type(Octstr *data) {
00241 long bitpos;
00242 long lastpos = -1;
00243 long lastnumbits = -1;
00244 long lastval = -1;
00245 int thistype;
00246
00247
00248
00249
00250
00251
00252
00253 #define PDU(name, docstring, fields, is_valid) \
00254 bitpos = 0; \
00255 thistype = name; \
00256 fields
00257 #define UINT(field, docstring, bits) bitpos += (bits);
00258 #define UINTVAR(field, docstring)
00259 #define OCTSTR(field, docstring, lengthfield)
00260 #define REST(field, docstring)
00261 #define TYPE(bits, value) \
00262 if ((bits) != lastnumbits || bitpos != lastpos) { \
00263 lastval = octstr_get_bits(data, bitpos, (bits)); \
00264 } \
00265 if (lastval == (value)) \
00266 return thistype; \
00267 lastnumbits = (bits); \
00268 lastpos = bitpos;
00269 #define RESERVED(bits) bitpos += (bits);
00270 #define TPI(confield)
00271 #include "wtp_pdu.def"
00272 #undef TPI
00273 #undef RESERVED
00274 #undef TYPE
00275 #undef REST
00276 #undef OCTSTR
00277 #undef UINTVAR
00278 #undef UINT
00279 #undef PDU
00280
00281 return -1;
00282 }
00283
00284 WTP_PDU *wtp_pdu_unpack(Octstr *data) {
00285 WTP_PDU *pdu = NULL;
00286 long bitpos = 0;
00287
00288 gw_assert(data != NULL);
00289
00290 pdu = gw_malloc(sizeof(*pdu));
00291
00292 pdu->type = wtp_pdu_type(data);
00293 pdu->options = NULL;
00294
00295 switch (pdu->type) {
00296 #define PDU(name, docstring, fields, is_valid) \
00297 case name: { \
00298 struct name *p = &pdu->u.name; \
00299 fields \
00300 gw_assert(bitpos % 8 == 0); \
00301 if (bitpos / 8 != octstr_len(data)) { \
00302 warning(0, "Bad length for " #name " PDU, " \
00303 "expected %ld", bitpos / 8); \
00304 } \
00305 if (!(is_valid)) { \
00306 warning(0, #name " PDU failed %s", #is_valid); \
00307 return NULL; \
00308 } \
00309 } break;
00310 #define UINT(field, docstring, bits) \
00311 p->field = octstr_get_bits(data, bitpos, (bits)); \
00312 bitpos += (bits);
00313 #define UINTVAR(field, docstring) \
00314 gw_assert(bitpos % 8 == 0); \
00315 p->field = octstr_get_bits(data, bitpos + 1, 7); \
00316 while (octstr_get_bits(data, bitpos, 1)) { \
00317 bitpos += 8; \
00318 p->field <<= 7; \
00319 p->field |= octstr_get_bits(data, bitpos + 1, 7); \
00320 } \
00321 bitpos += 8;
00322 #define OCTSTR(field, docstring, lengthfield) \
00323 gw_assert(bitpos % 8 == 0); \
00324 p->field = octstr_copy(data, bitpos / 8, p->lengthfield); \
00325 bitpos += 8 * p->lengthfield;
00326 #define REST(field, docstring) \
00327 gw_assert(bitpos % 8 == 0); \
00328 if (bitpos / 8 <= octstr_len(data)) { \
00329 p->field = octstr_copy(data, bitpos / 8, \
00330 octstr_len(data) - bitpos / 8); \
00331 bitpos = octstr_len(data) * 8; \
00332 } else { \
00333 p->field = octstr_create(""); \
00334 }
00335 #define TYPE(bits, value) bitpos += (bits);
00336 #define RESERVED(bits) bitpos += (bits);
00337 #define TPI(confield) \
00338 if (p->confield) { \
00339 pdu->options = gwlist_create(); \
00340 bitpos = unpack_tpis(data, bitpos, pdu); \
00341 }
00342 #include "wtp_pdu.def"
00343 #undef TPI
00344 #undef RESERVED
00345 #undef TYPE
00346 #undef REST
00347 #undef OCTSTR
00348 #undef UINTVAR
00349 #undef UINT
00350 #undef PDU
00351 default:
00352 warning(0, "WTP PDU with unknown type %d", pdu->type);
00353 gw_free(pdu);
00354 return NULL;
00355 }
00356
00357 return pdu;
00358 }
00359
00360 static void fixup_length_fields(WTP_PDU *pdu) {
00361 switch (pdu->type) {
00362 #define PDU(name, docstring, fields, is_valid) \
00363 case name: { \
00364 struct name *p = &pdu->u.name; \
00365 fields \
00366 } break;
00367 #define UINT(field, docstring, bits)
00368 #define UINTVAR(field, docstring)
00369 #define OCTSTR(field, docstring, lengthfield) \
00370 p->lengthfield = octstr_len(p->field);
00371 #define REST(field, docstring)
00372 #define TYPE(bits, value)
00373 #define RESERVED(bits)
00374 #define TPI(confield) \
00375 p->confield = pdu->options != NULL && gwlist_len(pdu->options) > 0;
00376 #include "wtp_pdu.def"
00377 #undef TPI
00378 #undef RESERVED
00379 #undef TYPE
00380 #undef REST
00381 #undef OCTSTR
00382 #undef UINTVAR
00383 #undef UINT
00384 #undef PDU
00385 }
00386 }
00387
00388 Octstr *wtp_pdu_pack(WTP_PDU *pdu) {
00389 Octstr *data;
00390 long bitpos;
00391
00392
00393 data = octstr_create("");
00394
00395 fixup_length_fields(pdu);
00396
00397 bitpos = 0;
00398 switch (pdu->type) {
00399 #define PDU(name, docstring, fields, is_valid) \
00400 case name: { \
00401 struct name *p = &pdu->u.name; \
00402 fields \
00403 gw_assert(bitpos % 8 == 0); \
00404 } break;
00405 #define UINT(field, docstring, bits) \
00406 octstr_set_bits(data, bitpos, (bits), p->field); \
00407 bitpos += (bits);
00408 #define UINTVAR(field, docstring) \
00409 gw_assert(bitpos % 8 == 0); \
00410 octstr_append_uintvar(data, p->field); \
00411 bitpos = 8 * octstr_len(data);
00412 #define OCTSTR(field, docstring, lengthfield) \
00413 gw_assert(bitpos % 8 == 0); \
00414 if (p->field != NULL) \
00415 octstr_append(data, p->field); \
00416 bitpos += 8 * octstr_len(p->field);
00417 #define REST(field, docstring) \
00418 gw_assert(bitpos % 8 == 0); \
00419 if (p->field != NULL) \
00420 octstr_append(data, p->field); \
00421 bitpos += 8 * octstr_len(p->field);
00422 #define TYPE(bits, value) \
00423 octstr_set_bits(data, bitpos, (bits), (value)); \
00424 bitpos += (bits);
00425 #define RESERVED(bits) bitpos += (bits);
00426 #define TPI(confield) \
00427 if (p->confield) { \
00428 bitpos = pack_tpis(data, bitpos, pdu->options); \
00429 }
00430 #include "wtp_pdu.def"
00431 #undef TPI
00432 #undef RESERVED
00433 #undef TYPE
00434 #undef REST
00435 #undef OCTSTR
00436 #undef UINTVAR
00437 #undef UINT
00438 #undef PDU
00439 default:
00440 panic(0, "Packing unknown WTP PDU type %ld", (long) pdu->type);
00441 }
00442
00443 return data;
00444 }
00445
00446 void wtp_pdu_dump(WTP_PDU *pdu, int level) {
00447 char *dbg = "wap.wtp";
00448
00449 switch (pdu->type) {
00450 #define PDU(name, docstring, fields, is_valid) \
00451 case name: { \
00452 struct name *p = &pdu->u.name; \
00453 debug(dbg, 0, "%*sWTP %s PDU at %p:", \
00454 level, "", #name, (void *)pdu); \
00455 fields \
00456 } break;
00457 #define UINT(field, docstring, bits) \
00458 debug(dbg, 0, "%*s %s: %lu", level, "", docstring, p->field);
00459 #define UINTVAR(field, docstring) \
00460 debug(dbg, 0, "%*s %s: %lu", level, "", docstring, p->field);
00461 #define OCTSTR(field, docstring, lengthfield) \
00462 debug(dbg, 0, "%*s %s:", level, "", docstring); \
00463 octstr_dump(p->field, level + 1);
00464 #define REST(field, docstring) \
00465 debug(dbg, 0, "%*s %s:", level, "", docstring); \
00466 octstr_dump(p->field, level + 1);
00467 #define TYPE(bits, value)
00468 #define RESERVED(bits)
00469 #define TPI(confield) dump_tpis(pdu->options, level);
00470 #include "wtp_pdu.def"
00471 #undef TPI
00472 #undef RESERVED
00473 #undef TYPE
00474 #undef REST
00475 #undef OCTSTR
00476 #undef UINTVAR
00477 #undef UINT
00478 #undef PDU
00479 default:
00480 debug(dbg, 0, "%*sWTP PDU at %p:", level, "", (void *)pdu);
00481 debug(dbg, 0, "%*s unknown type %u", level, "", pdu->type);
00482 break;
00483 }
00484 }
See file LICENSE for details about the license agreement for using,
modifying, copying or deriving work from this software.