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 /* wsp_pdu.c - pack and unpack WSP packets
58 *
59 * Generates packing and unpacking code from wsp_pdu.def.
60 * Code is very similar to wsp_pdu.c, please make any changes in both files.
61 *
62 * Richard Braakman
63 */
64
65 #include "gwlib/gwlib.h"
66 #include "wsp_pdu.h"
67
wsp_pdu_create(int type)68 WSP_PDU *wsp_pdu_create(int type) {
69 WSP_PDU *pdu;
70
71 pdu = gw_malloc(sizeof(*pdu));
72 pdu->type = type;
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 #include "wsp_pdu.def"
87 #undef RESERVED
88 #undef TYPE
89 #undef REST
90 #undef OCTSTR
91 #undef UINTVAR
92 #undef UINT
93 #undef PDU
94 default:
95 panic(0, "Internal error: Unknown PDU type %d", pdu->type);
96 break;
97 }
98
99 return pdu;
100 }
101
wsp_pdu_destroy(WSP_PDU * pdu)102 void wsp_pdu_destroy(WSP_PDU *pdu) {
103 if (pdu == NULL)
104 return;
105
106 switch (pdu->type) {
107 #define PDU(name, docstring, fields, is_valid) \
108 case name: {\
109 struct name *p; p = &pdu->u.name; \
110 fields \
111 } break;
112 #define UINT(field, docstring, bits)
113 #define UINTVAR(field, docstring)
114 #define OCTSTR(field, docstring, lengthfield) octstr_destroy(p->field);
115 #define REST(field, docstring) octstr_destroy(p->field);
116 #define TYPE(bits, value)
117 #define RESERVED(bits)
118 #include "wsp_pdu.def"
119 #undef RESERVED
120 #undef TYPE
121 #undef REST
122 #undef OCTSTR
123 #undef UINTVAR
124 #undef UINT
125 #undef PDU
126 default:
127 panic(0, "Cannot destroy unknown WSP PDU type %d", pdu->type);
128 break;
129 }
130
131 gw_free(pdu);
132 }
133
134 /* Determine which type of PDU this is, using the TYPE macros in
135 * the definition file. */
wsp_pdu_type(Octstr * data)136 static int wsp_pdu_type(Octstr *data) {
137 long bitpos;
138 long lastpos = -1;
139 long lastnumbits = -1;
140 long lastval = -1;
141 int thistype;
142
143 /* This code looks slow, but an optimizing compiler will
144 * reduce it considerably. gcc -O2 will produce a single
145 * call to octstr_get_bits, folllowed by a sequence of
146 * tests on lastval. */
147
148 /* Only UINT and RESERVED fields may precede the TYPE */
149 #define PDU(name, docstring, fields, is_valid) \
150 bitpos = 0; \
151 thistype = name; \
152 fields
153 #define UINT(field, docstring, bits) bitpos += (bits);
154 #define UINTVAR(field, docstring)
155 #define OCTSTR(field, docstring, lengthfield)
156 #define REST(field, docstring)
157 #define TYPE(bits, value) \
158 if ((bits) != lastnumbits || bitpos != lastpos) { \
159 lastval = octstr_get_bits(data, bitpos, (bits)); \
160 } \
161 if (lastval == (value)) \
162 return thistype; \
163 lastnumbits = (bits); \
164 lastpos = bitpos;
165 #define RESERVED(bits) bitpos += (bits);
166 #include "wsp_pdu.def"
167 #undef RESERVED
168 #undef TYPE
169 #undef REST
170 #undef OCTSTR
171 #undef UINTVAR
172 #undef UINT
173 #undef PDU
174
175 return -1;
176 }
177
wsp_pdu_unpack(Octstr * data)178 WSP_PDU *wsp_pdu_unpack(Octstr *data) {
179 WSP_PDU *pdu = NULL;
180 long bitpos = 0;
181
182 gw_assert(data != NULL);
183
184 pdu = gw_malloc(sizeof(*pdu));
185
186 pdu->type = wsp_pdu_type(data);
187
188 switch (pdu->type) {
189 #define PDU(name, docstring, fields, is_valid) \
190 case name: { \
191 struct name *p = &pdu->u.name; \
192 fields \
193 gw_assert(bitpos % 8 == 0); \
194 if (bitpos / 8 != octstr_len(data)) { \
195 warning(0, "Bad length for " #name " PDU, " \
196 "expected %ld", bitpos / 8); \
197 } \
198 if (!(is_valid)) { \
199 warning(0, #name " PDU failed %s", #is_valid); \
200 } \
201 } break;
202 #define UINT(field, docstring, bits) \
203 p->field = octstr_get_bits(data, bitpos, (bits)); \
204 bitpos += (bits);
205 #define UINTVAR(field, docstring) \
206 gw_assert(bitpos % 8 == 0); \
207 p->field = octstr_get_bits(data, bitpos + 1, 7); \
208 while (octstr_get_bits(data, bitpos, 1)) { \
209 bitpos += 8; \
210 p->field <<= 7; \
211 p->field |= octstr_get_bits(data, bitpos + 1, 7); \
212 } \
213 bitpos += 8;
214 #define OCTSTR(field, docstring, lengthfield) \
215 gw_assert(bitpos % 8 == 0); \
216 p->field = octstr_copy(data, bitpos / 8, p->lengthfield); \
217 bitpos += 8 * p->lengthfield;
218 #define REST(field, docstring) \
219 gw_assert(bitpos % 8 == 0); \
220 if (bitpos / 8 <= octstr_len(data)) { \
221 p->field = octstr_copy(data, bitpos / 8, \
222 octstr_len(data) - bitpos / 8); \
223 bitpos = octstr_len(data) * 8; \
224 } else { \
225 p->field = octstr_create(""); \
226 }
227 #define TYPE(bits, value) bitpos += (bits);
228 #define RESERVED(bits) bitpos += (bits);
229 #include "wsp_pdu.def"
230 #undef RESERVED
231 #undef TYPE
232 #undef REST
233 #undef OCTSTR
234 #undef UINTVAR
235 #undef UINT
236 #undef PDU
237 default:
238 warning(0, "WSP PDU with unknown type %d", pdu->type);
239 gw_free(pdu);
240 return NULL;
241 }
242
243 return pdu;
244 }
245
fixup_length_fields(WSP_PDU * pdu)246 static void fixup_length_fields(WSP_PDU *pdu) {
247 switch (pdu->type) {
248 #define PDU(name, docstring, fields, is_valid) \
249 case name: { \
250 struct name *p; p = &pdu->u.name; \
251 fields \
252 } break;
253 #define UINT(field, docstring, bits)
254 #define UINTVAR(field, docstring)
255 #define OCTSTR(field, docstring, lengthfield) \
256 p->lengthfield = octstr_len(p->field);
257 #define REST(field, docstring)
258 #define TYPE(bits, value)
259 #define RESERVED(bits)
260 #include "wsp_pdu.def"
261 #undef RESERVED
262 #undef TYPE
263 #undef REST
264 #undef OCTSTR
265 #undef UINTVAR
266 #undef UINT
267 #undef PDU
268 }
269 }
270
wsp_pdu_pack(WSP_PDU * pdu)271 Octstr *wsp_pdu_pack(WSP_PDU *pdu) {
272 Octstr *data;
273 long bitpos;
274
275 /* We rely on octstr_set_bits to lengthen our octstr as needed. */
276 data = octstr_create("");
277
278 fixup_length_fields(pdu);
279
280 bitpos = 0;
281 switch (pdu->type) {
282 #define PDU(name, docstring, fields, is_valid) \
283 case name: { \
284 struct name *p = &pdu->u.name; \
285 fields \
286 gw_assert(bitpos % 8 == 0); \
287 } break;
288 #define UINT(field, docstring, bits) \
289 octstr_set_bits(data, bitpos, (bits), p->field); \
290 bitpos += (bits);
291 #define UINTVAR(field, docstring) \
292 gw_assert(bitpos % 8 == 0); \
293 octstr_append_uintvar(data, p->field); \
294 bitpos = 8 * octstr_len(data);
295 #define OCTSTR(field, docstring, lengthfield) \
296 gw_assert(bitpos % 8 == 0); \
297 if (p->field != NULL) \
298 octstr_append(data, p->field); \
299 bitpos += 8 * octstr_len(p->field);
300 #define REST(field, docstring) \
301 gw_assert(bitpos % 8 == 0); \
302 if (p->field != NULL) \
303 octstr_append(data, p->field); \
304 bitpos += 8 * octstr_len(p->field);
305 #define TYPE(bits, value) \
306 octstr_set_bits(data, bitpos, (bits), (value)); \
307 bitpos += (bits);
308 #define RESERVED(bits) bitpos += (bits);
309 #include "wsp_pdu.def"
310 #undef RESERVED
311 #undef TYPE
312 #undef REST
313 #undef OCTSTR
314 #undef UINTVAR
315 #undef UINT
316 #undef PDU
317 default:
318 panic(0, "Packing unknown WSP PDU type %ld", (long) pdu->type);
319 }
320
321 return data;
322 }
323
wsp_pdu_dump(WSP_PDU * pdu,int level)324 void wsp_pdu_dump(WSP_PDU *pdu, int level) {
325 char *dbg = "wap.wsp";
326
327 switch (pdu->type) {
328 #define PDU(name, docstring, fields, is_valid) \
329 case name: { \
330 struct name *p = &pdu->u.name; \
331 debug(dbg, 0, "%*sWSP %s PDU at %p:", \
332 level, "", #name, (void *)pdu); \
333 fields \
334 } break;
335 #define UINT(field, docstring, bits) \
336 debug(dbg, 0, "%*s %s: %lu", level, "", docstring, p->field);
337 #define UINTVAR(field, docstring) \
338 debug(dbg, 0, "%*s %s: %lu", level, "", docstring, p->field);
339 #define OCTSTR(field, docstring, lengthfield) \
340 debug(dbg, 0, "%*s %s:", level, "", docstring); \
341 octstr_dump(p->field, level + 1);
342 #define REST(field, docstring) \
343 debug(dbg, 0, "%*s %s:", level, "", docstring); \
344 octstr_dump(p->field, level + 1);
345 #define TYPE(bits, value)
346 #define RESERVED(bits)
347 #include "wsp_pdu.def"
348 #undef RESERVED
349 #undef TYPE
350 #undef REST
351 #undef OCTSTR
352 #undef UINTVAR
353 #undef UINT
354 #undef PDU
355 default:
356 debug(dbg, 0, "%*sWSP PDU at %p:", level, "", (void *)pdu);
357 debug(dbg, 0, "%*s unknown type %u", level, "", pdu->type);
358 break;
359 }
360 debug("wap.wsp", 0, "%*sWSP PDU dump ends.", level, "");
361 }
362