85048bcdeb9e2d787c251bb6caa94c22fc05e015
[obnox/wireshark/wip.git] / epan / dissectors / packet-cmpp.c
1 /* packet-cmpp.c
2  * Routines for China Mobile Point to Point dissection
3  * Copyright 2007, Andy Chu <chu.dev@gmail.com>
4  *
5  * $Id$
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <stdlib.h>
31
32 #include <epan/packet.h>
33 #include <epan/dissectors/packet-tcp.h>
34
35 #define CMPP_FIX_HEADER_LENGTH 12
36 #define CMPP_DELIVER_REPORT_LEN 71
37
38 /* These are not registered with IANA */
39 #define CMPP_SP_LONG_PORT 7890
40 #define CMPP_SP_SHORT_PORT 7900
41 #define CMPP_ISMG_LONG_PORT 7930
42 #define CMPP_ISMG_SHORT_PORT 9168
43
44 /* Initialize the protocol and registered fields */
45 static gint proto_cmpp = -1;
46
47 /* These are the fix header field */
48 static gint hf_cmpp_Total_Length = -1;
49 static gint hf_cmpp_Command_Id = -1;
50 static gint hf_cmpp_Sequence_Id = -1;
51
52 /* CMPP_CONNECT */
53 static gint hf_cmpp_connect_Source_Addr = -1;
54 static gint hf_cmpp_connect_AuthenticatorSource = -1;
55 static gint hf_cmpp_Version = -1;
56 static gint hf_cmpp_connect_Timestamp = -1;
57
58 /* CMPP_CONNECT_RESP */
59 static gint hf_cmpp_connect_resp_status = -1;
60 static gint hf_cmpp_connect_resp_AuthenticatorISMG = -1;
61
62 /* CMPP_SUBMIT */
63 static gint hf_cmpp_submit_pk_total = -1;
64 static gint hf_cmpp_submit_pk_number = -1;
65 static gint hf_cmpp_submit_Msg_level = -1;
66 static gint hf_cmpp_submit_Fee_UserType = -1;
67 static gint hf_cmpp_submit_Fee_terminal_Id = -1;
68 static gint hf_cmpp_submit_Fee_terminal_type = -1;
69 static gint hf_cmpp_submit_Msg_src = -1;
70 static gint hf_cmpp_submit_FeeType = -1;
71 static gint hf_cmpp_submit_FeeCode = -1;
72 static gint hf_cmpp_submit_Valld_Time = -1;
73 static gint hf_cmpp_submit_At_Time = -1;
74 static gint hf_cmpp_submit_Src_Id = -1;
75 static gint hf_cmpp_submit_DestUsr_tl = -1;
76 static gint hf_cmpp_submit_Dest_terminal_type = -1;
77 static gint hf_cmpp_submit_Registered_Delivery = -1;
78
79 /* Field common in CMPP_SUBMIT and CMPP_DELIVER */
80 static gint hf_cmpp_Dest_terminal_Id = -1;
81 static gint hf_cmpp_Service_Id = -1;
82 static gint hf_cmpp_TP_pId = -1;
83 static gint hf_cmpp_TP_udhi = -1;
84 static gint hf_cmpp_Msg_Fmt = -1;
85 static gint hf_cmpp_Msg_Length = -1;
86 static gint hf_cmpp_Msg_Content = -1;
87 static gint hf_cmpp_LinkID = -1;
88
89 /* CMPP_SUBMIT_RESP */
90 static gint hf_cmpp_submit_resp_Result = -1;
91
92 /* CMPP_QUERY */
93 /* CMPP_QUERY_RESP */
94 /* TODO implement CMPP_QUERY and CMPP_QUERY_RESP */
95
96 /* CMPP_DELIVER */
97 static gint hf_cmpp_deliver_Dest_Id = -1;
98 static gint hf_cmpp_deliver_Src_terminal_Id = -1;
99 static gint hf_cmpp_deliver_Src_terminal_type = -1;
100 static gint hf_cmpp_deliver_Registered_Delivery = -1;
101
102 static gint hf_cmpp_deliver_resp_Result = -1;
103
104 /* CMPP Deliver Report */
105 static gint hf_cmpp_deliver_Report = -1;
106 static gint hf_cmpp_deliver_Report_Stat = -1;
107 static gint hf_cmpp_deliver_Report_Submit_time = -1;
108 static gint hf_cmpp_deliver_Report_Done_time = -1;
109 static gint hf_cmpp_deliver_Report_SMSC_sequence = -1;
110
111 /* Msg_Id field */
112 static gint hf_cmpp_msg_id = -1;
113 static gint hf_msg_id_timestamp = -1;
114 static gint hf_msg_id_ismg_code = -1;
115 static gint hf_msg_id_sequence_id = -1;
116
117 static gboolean cmpp_desegment = TRUE;
118
119 /*
120  * Value-arrays for field-contents
121  */
122 #define CMPP_CONNECT                    0x00000001
123 #define CMPP_CONNECT_RESP               0x80000001
124 #define CMPP_TERMINATE                  0x00000002
125 #define CMPP_TERMINATE_RESP             0x80000002
126 #define CMPP_SUBMIT                     0x00000004
127 #define CMPP_SUBMIT_RESP                0x80000004
128 #define CMPP_DELIVER                    0x00000005
129 #define CMPP_DELIVER_RESP               0x80000005
130 #define CMPP_QUERY                      0x00000006
131 #define CMPP_QUERY_RESP                 0x80000006
132 #define CMPP_CANCEL                     0x00000007
133 #define CMPP_CANCEL_RESP                0x80000007
134 #define CMPP_ACTIVE_TEST                0x00000008
135 #define CMPP_ACTIVE_TEST_RESP           0x80000008
136 #define CMPP_FWD                        0x00000009
137 #define CMPP_FWD_RESP                   0x80000009
138 #define CMPP_MT_ROUTE                   0x00000010
139 #define CMPP_MO_ROUTE                   0x00000011
140 #define CMPP_GET_MT_ROUTE               0x00000012
141 #define CMPP_MT_ROUTE_UPDATE            0x00000013
142 #define CMPP_MO_ROUTE_UPDATE            0x00000014
143 #define CMPP_PUSH_MT_ROUTE_UPDATE       0x00000015
144 #define CMPP_PUSH_MO_ROUTE_UPDATE       0x00000016
145 #define CMPP_GET_MO_ROUTE               0x00000017
146 #define CMPP_MT_ROUTE_RESP              0x80000010
147 #define CMPP_MO_ROUTE_RESP              0x80000011
148 #define CMPP_GET_MT_ROUTE_RESP          0x80000012
149 #define CMPP_MT_ROUTE_UPDATE_RESP       0x80000013
150 #define CMPP_MO_ROUTE_UPDATE_RESP       0x80000014
151 #define CMPP_PUSH_MT_ROUTE_UPDATE_RESP  0x80000015
152 #define CMPP_PUSH_MO_ROUTE_UPDATE_RESP  0x80000016
153 #define CMPP_GET_MO_ROUTE_RESP          0x80000017
154 static const value_string vals_command_Id[] = {         /* Operation    */
155     { CMPP_CONNECT, "CMPP_CONNECT" },
156     { CMPP_CONNECT_RESP, "CMPP_CONNECT_RESP" },
157     { CMPP_TERMINATE, "CMPP_TERMINATE" },
158     { CMPP_TERMINATE_RESP, "CMPP_TERMINATE_RESP" },
159     { CMPP_SUBMIT, "CMPP_SUBMIT" },
160     { CMPP_SUBMIT_RESP, "CMPP_SUBMIT_RESP" },
161     { CMPP_DELIVER, "CMPP_DELIVER" },
162     { CMPP_DELIVER_RESP, "CMPP_DELIVER_RESP" },
163     { CMPP_QUERY, "CMPP_QUERY" },
164     { CMPP_QUERY_RESP, "CMPP_QUERY" },
165     { CMPP_CANCEL, "CMPP_CANCEL" },
166     { CMPP_CANCEL_RESP, "CMPP_CANCEL_RESP" },
167     { CMPP_ACTIVE_TEST, "CMPP_ACTIVE_TEST" },
168     { CMPP_ACTIVE_TEST_RESP, "CMPP_ACTIVE_TEST_RESP" },
169     { CMPP_FWD, "CMPP_FWD" },
170     { CMPP_FWD_RESP, "CMPP_FWD_RESP" },
171     { CMPP_MT_ROUTE, "CMPP_MT_ROUTE" },
172     { CMPP_MO_ROUTE, "CMPP_MO_ROUTE" },
173     { CMPP_GET_MT_ROUTE, "CMPP_GET_MT_ROUTE" },
174     { CMPP_MT_ROUTE_UPDATE, "CMPP_MT_ROUTE_UPDATE" },
175     { CMPP_MO_ROUTE_UPDATE, "CMPP_MO_ROUTE_UPDATE" },
176     { CMPP_PUSH_MT_ROUTE_UPDATE, "CMPP_PUSH_MT_ROUTE_UPDATE" },
177     { CMPP_PUSH_MO_ROUTE_UPDATE, "CMPP_PUSH_MO_ROUTE_UPDATE" },
178     { CMPP_GET_MO_ROUTE, "CMPP_GET_MO_ROUTE" },
179     { CMPP_MT_ROUTE_RESP, "CMPP_MT_ROUTE_RESP" },
180     { CMPP_MO_ROUTE_RESP, "CMPP_MO_ROUTE_RESP" },
181     { CMPP_GET_MT_ROUTE_RESP, "CMPP_GET_MT_ROUTE_RESP" },
182     { CMPP_MT_ROUTE_UPDATE_RESP, "CMPP_MT_ROUTE_UPDATE_RESP" },
183     { CMPP_MO_ROUTE_UPDATE_RESP, "CMPP_MO_ROUTE_UPDATE_RESP" },
184     { CMPP_PUSH_MT_ROUTE_UPDATE_RESP, "CMPP_PUSH_MT_ROUTE_UPDATE_RESP" },
185     { CMPP_PUSH_MO_ROUTE_UPDATE_RESP, "CMPP_PUSH_MO_ROUTE_UPDATE_RESP" },
186     { CMPP_GET_MO_ROUTE_RESP, "CMPP_GET_MO_ROUTE_RESP" },
187     { 0, NULL }
188 };
189
190 static const value_string vals_connect_resp_status[] = {        /* Connection Status */
191         { 0, "Correct" },
192         { 1, "Message structure error" },
193         { 2, "Illegal source address" },
194         { 3, "Authenticate error" },
195         { 4, "Version too high" },
196         { 0, NULL }
197 };
198
199 static const value_string vals_submit_Fee_UserType[] = { /* Submit Fee_UserType */
200         { 0, "Charging destination MSISDN" },
201         { 1, "Charging source MSISDN" },
202         { 2, "Charging SP" },
203         { 3, "Unuse, Charge info from Fee_terminal_Id" },
204         { 0, NULL }
205 };
206
207 static const value_string vals_Msg_Fmt[] = { /* Message Format */
208         { 0, "ASCII" },
209         { 3, "Short message card" }, /* TODO find the correct string of this value */
210         { 4, "Binary data" },
211         { 8, "UCS2 encoding" },
212         {15, "GB encoding" },
213         { 0, NULL }
214 };
215
216 /* Submit Response Result */
217 static const value_string vals_Submit_Resp_Result[] = {
218         { 0, "Correct" },
219         { 1, "Message format error" },
220         { 2, "Command error" },
221         { 3, "Repeat sequence id" },
222         { 4, "Incorrect message length" },
223         { 5, "Incorrect fee code" },
224         { 6, "Message too long" },
225         { 7, "Incorrect service id" },
226         { 8, "Bandwidth error" },
227         { 9, "Gateway does not service this charging number" },
228         {10, "Incorrect Src_Id" },
229         {11, "Incorrect Msg_src" },
230         {12, "Incorrect Fee_terminal_Id" },
231         {13, "Incorrect Dest_terminal_Id" },
232         { 0, NULL }
233 };
234
235 /* Deliver Response Result */
236 static const value_string vals_Deliver_Resp_Result[] = {
237         { 0, "Correct" },
238         { 1, "Message format error" },
239         { 2, "Command error" },
240         { 3, "Repeat sequence id" },
241         { 4, "Incorrect message length" },
242         { 5, "Incorrect fee code" },
243         { 6, "Message too long" },
244         { 7, "Incorrect service id" },
245         { 8, "Bandwidth error" },
246         { 0, NULL }
247 };
248
249 /* Initialize the subtree pointers */
250 static gint ett_cmpp = -1;
251 static gint ett_msg_id = -1;
252 static gint ett_deliver_report = -1;
253
254 /* Helper functions */
255
256 static char*
257 cmpp_octet_string(proto_tree *tree, tvbuff_t *tvb, gint field, gint offset, gint length)
258 {
259         char *display;
260
261         display = (char *)tvb_get_ephemeral_string(tvb, offset, length);
262         proto_tree_add_string(tree, field, tvb, offset, length, display);
263         return display;
264 }
265
266 static char*
267 cmpp_version(proto_tree *tree, tvbuff_t *tvb, gint  field, gint offset)
268 {
269         gint8 version, major, minor;
270         char *strval;
271
272         version = tvb_get_guint8(tvb, offset);
273         minor = version & 0x0F;
274         major = (version & 0xF0) >> 4;
275         strval = ep_strdup_printf("%02u.%02u", major, minor);
276         /* TODO: the version should be added as a uint_format */
277         proto_tree_add_string(tree, field, tvb, offset, 1, strval);
278         return strval;
279 }
280
281 static char*
282 cmpp_timestamp(proto_tree *tree, tvbuff_t *tvb, gint  field, gint offset)
283 {
284         gint8 month, day, hour, minute, second;
285         gint32 timevalue;
286         char *strval;
287
288         timevalue = tvb_get_ntohl(tvb, offset);
289         second = timevalue % 100;
290         timevalue /= 100;
291         minute = timevalue % 100;
292         timevalue /= 100;
293         hour = timevalue % 100;
294         timevalue /= 100;
295         day = timevalue % 100;
296         month = timevalue / 100;
297         strval = ep_strdup_printf("%02u/%02u %02u:%02u:%02u", month, day,
298                 hour, minute, second);
299         proto_tree_add_string(tree, field, tvb, offset, 4, strval);
300         return strval;
301 }
302
303 /*  TODO: most calls to these (except those that use the return value) should
304  *  be replaced by calls to proto_tree_add_item().
305  */
306 static guint8
307 cmpp_uint1(proto_tree *tree, tvbuff_t *tvb, gint  field, gint offset)
308 {
309         guint8 value;
310         value = tvb_get_guint8(tvb, offset);
311         proto_tree_add_uint(tree, field, tvb, offset, 1, value);
312         return value;
313 }
314
315 static guint16
316 cmpp_uint2(proto_tree *tree, tvbuff_t *tvb, gint  field, gint offset)
317 {
318         guint16 value;
319         value = tvb_get_ntohs(tvb, offset);
320         proto_tree_add_uint(tree, field, tvb, offset, 2, value);
321         return value;
322 }
323
324 static gint32
325 cmpp_uint4(proto_tree *tree, tvbuff_t *tvb, gint  field, gint offset)
326 {
327         gint32 value;
328         value = tvb_get_ntohl(tvb, offset);
329         proto_tree_add_uint(tree, field, tvb, offset, 4, value);
330         return value;
331 }
332
333 static gboolean
334 cmpp_boolean(proto_tree *tree, tvbuff_t *tvb, gint  field, gint offset)
335 {
336         gint8 value;
337         value = tvb_get_guint8(tvb, offset);
338         proto_tree_add_boolean(tree, field, tvb, offset, 1, value);
339         if (value ==  1)
340                 return TRUE;
341         return FALSE;
342 }
343
344 static void
345 cmpp_msg_id(proto_tree *tree, tvbuff_t *tvb, gint  field, gint offset)
346 {
347         guint8 month,day,hour,minute,second;
348         guint32 ismg_code;
349         proto_item *pi;
350         proto_tree *sub_tree;
351         char *strval;
352
353         pi = proto_tree_add_item(tree, field, tvb, offset, 8, ENC_BIG_ENDIAN);
354         sub_tree = proto_item_add_subtree(pi, ett_msg_id);
355
356         month = (tvb_get_guint8(tvb, offset) & 0xF0) >> 4;
357         day = (tvb_get_ntohs(tvb, offset) & 0x0F80) >> 7;
358         hour = (tvb_get_guint8(tvb, offset + 1) & 0x7C) >> 2;
359         minute = (tvb_get_ntohs(tvb, offset + 1) & 0x03F0) >> 4;
360         second = (tvb_get_ntohs(tvb, offset + 2) & 0x0FC0) >> 6;
361         strval = ep_strdup_printf("%02u/%02u %02u:%02u:%02u", month, day,
362                 hour, minute, second);
363
364         ismg_code = (tvb_get_ntohl(tvb, offset + 3) & 0x3FFFFF00) >> 16;
365
366         proto_tree_add_string(sub_tree, hf_msg_id_timestamp, tvb, offset, 4, strval);
367         proto_tree_add_uint(sub_tree, hf_msg_id_ismg_code, tvb, offset + 3, 3, ismg_code);
368         cmpp_uint2(sub_tree, tvb, hf_msg_id_sequence_id, offset + 6);
369 }
370
371 static void
372 cmpp_connect(proto_tree *tree, tvbuff_t *tvb)
373 {
374         int offset;
375         offset = CMPP_FIX_HEADER_LENGTH;
376         cmpp_octet_string(tree, tvb, hf_cmpp_connect_Source_Addr, offset, 6);
377         offset += 6;
378         proto_tree_add_string(tree, hf_cmpp_connect_AuthenticatorSource, tvb, offset, 16, "MD5 Hash");
379         offset += 16;
380         cmpp_version(tree, tvb, hf_cmpp_Version, offset);
381         offset += 1;
382         cmpp_timestamp(tree, tvb, hf_cmpp_connect_Timestamp, offset);
383 }
384
385
386 static void
387 cmpp_connect_resp(proto_tree *tree, tvbuff_t *tvb)
388 {
389         int offset;
390         offset = CMPP_FIX_HEADER_LENGTH;
391         cmpp_uint4(tree, tvb, hf_cmpp_connect_resp_status, offset);
392         offset += 4;
393         proto_tree_add_string(tree, hf_cmpp_connect_resp_AuthenticatorISMG, tvb, offset, 16, "MD5 Hash");
394         offset += 16;
395         cmpp_version(tree, tvb, hf_cmpp_Version, offset);
396 }
397
398 static void
399 cmpp_submit(proto_tree *tree, tvbuff_t *tvb)
400 {
401         int offset, i;
402         guint8 destUsr, msgLen;
403         offset = CMPP_FIX_HEADER_LENGTH;
404         cmpp_msg_id(tree, tvb, hf_cmpp_msg_id, offset);
405         offset += 8;
406         cmpp_uint1(tree, tvb, hf_cmpp_submit_pk_total, offset);
407         offset++;
408         cmpp_uint1(tree, tvb, hf_cmpp_submit_pk_number, offset);
409         offset++;
410         cmpp_boolean(tree, tvb, hf_cmpp_submit_Registered_Delivery, offset);
411         offset++;
412         cmpp_uint1(tree, tvb, hf_cmpp_submit_Msg_level, offset);
413         offset++;
414         cmpp_octet_string(tree, tvb, hf_cmpp_Service_Id, offset, 10);
415         offset += 10;
416         cmpp_uint1(tree, tvb, hf_cmpp_submit_Fee_UserType, offset);
417         offset++;
418         cmpp_octet_string(tree, tvb, hf_cmpp_submit_Fee_terminal_Id, offset, 32);
419         offset+=32;
420         cmpp_boolean(tree, tvb, hf_cmpp_submit_Fee_terminal_type, offset);
421         offset++;
422         cmpp_uint1(tree, tvb, hf_cmpp_TP_pId, offset);
423         offset++;
424         cmpp_uint1(tree, tvb, hf_cmpp_TP_udhi, offset);
425         offset++;
426         cmpp_uint1(tree, tvb, hf_cmpp_Msg_Fmt, offset);
427         offset++;
428         cmpp_octet_string(tree, tvb, hf_cmpp_submit_Msg_src, offset, 6);
429         offset += 6;
430         cmpp_octet_string(tree, tvb, hf_cmpp_submit_FeeType, offset, 2);
431         offset += 2;
432         cmpp_octet_string(tree, tvb, hf_cmpp_submit_FeeCode, offset, 6);
433         offset += 6;
434
435         /* TODO create function to handle SMPP time format */
436         cmpp_octet_string(tree, tvb, hf_cmpp_submit_Valld_Time, offset, 17);
437         offset += 17;
438         cmpp_octet_string(tree, tvb, hf_cmpp_submit_At_Time, offset, 17);
439         offset += 17;
440
441         cmpp_octet_string(tree, tvb, hf_cmpp_submit_Src_Id, offset, 17);
442         offset += 21;
443         destUsr = cmpp_uint1(tree, tvb, hf_cmpp_submit_DestUsr_tl, offset);
444         offset++;
445
446         /* Loop through each destination address */
447         for(i = 0; i < destUsr; i++)
448         {
449                 cmpp_octet_string(tree, tvb, hf_cmpp_Dest_terminal_Id, offset, 32);
450                 offset += 32;
451         }
452
453         cmpp_boolean(tree, tvb, hf_cmpp_submit_Dest_terminal_type, offset);
454         offset++;
455         msgLen = cmpp_uint1(tree, tvb, hf_cmpp_Msg_Length, offset);
456         offset++;
457         proto_tree_add_string(tree, hf_cmpp_Msg_Content, tvb, offset, msgLen, "SMS Messages");
458         offset += msgLen;
459         cmpp_octet_string(tree, tvb, hf_cmpp_LinkID, offset, 20);
460 }
461
462 static void
463 cmpp_submit_resp(proto_tree *tree, tvbuff_t *tvb)
464 {
465         int offset;
466         offset = CMPP_FIX_HEADER_LENGTH;
467         cmpp_msg_id(tree, tvb, hf_cmpp_msg_id, offset);
468         offset += 8;
469         cmpp_uint4(tree, tvb, hf_cmpp_submit_resp_Result, offset);
470 }
471
472 static void
473 cmpp_deliver_report(proto_tree *tree, tvbuff_t *tvb, gint  field, guint offset)
474 {
475         proto_item *pi;
476         proto_tree *sub_tree;
477
478         pi = proto_tree_add_item(tree, field, tvb, offset, CMPP_DELIVER_REPORT_LEN, ENC_BIG_ENDIAN);
479         sub_tree = proto_item_add_subtree(pi, ett_deliver_report);
480         cmpp_msg_id(sub_tree, tvb, hf_cmpp_msg_id, offset);
481         offset += 8;
482         cmpp_octet_string(sub_tree, tvb, hf_cmpp_deliver_Report_Stat, offset, 7);
483         offset += 7;
484         cmpp_octet_string(sub_tree, tvb, hf_cmpp_deliver_Report_Submit_time, offset, 10);
485         offset += 10;
486         cmpp_octet_string(sub_tree, tvb, hf_cmpp_deliver_Report_Done_time, offset, 10);
487         offset += 10;
488         cmpp_octet_string(sub_tree, tvb, hf_cmpp_Dest_terminal_Id, offset, 32);
489         offset += 32;
490         cmpp_uint4(sub_tree, tvb, hf_cmpp_deliver_Report_SMSC_sequence, offset);
491 }
492
493 static void
494 cmpp_deliver(proto_tree *tree, tvbuff_t *tvb)
495 {
496         guint offset, msgLen;
497         gboolean report;
498         offset = CMPP_FIX_HEADER_LENGTH;
499         cmpp_msg_id(tree, tvb, hf_cmpp_msg_id, offset);
500         offset += 8;
501         cmpp_octet_string(tree, tvb, hf_cmpp_deliver_Dest_Id, offset, 21);
502         offset += 21;
503         cmpp_octet_string(tree, tvb, hf_cmpp_Service_Id, offset, 10);
504         offset += 10;
505         cmpp_uint1(tree, tvb, hf_cmpp_TP_pId, offset);
506         offset++;
507         cmpp_uint1(tree, tvb, hf_cmpp_TP_udhi, offset);
508         offset++;
509         cmpp_uint1(tree, tvb, hf_cmpp_Msg_Fmt, offset);
510         offset++;
511         cmpp_octet_string(tree, tvb, hf_cmpp_deliver_Src_terminal_Id, offset, 32);
512         offset += 32;
513         cmpp_boolean(tree, tvb, hf_cmpp_deliver_Src_terminal_type, offset);
514         offset++;
515         report = cmpp_boolean(tree, tvb, hf_cmpp_deliver_Registered_Delivery, offset);
516         offset++;
517         msgLen = cmpp_uint1(tree, tvb, hf_cmpp_Msg_Length, offset);
518         offset++;
519         if (report == FALSE)
520                 proto_tree_add_string(tree, hf_cmpp_Msg_Content, tvb, offset, msgLen, "SMS Messages");
521         else
522                 cmpp_deliver_report(tree, tvb, hf_cmpp_deliver_Report, offset);
523         offset += msgLen;
524         cmpp_octet_string(tree, tvb, hf_cmpp_LinkID, offset, 20);
525 }
526
527 static void
528 cmpp_deliver_resp(proto_tree *tree, tvbuff_t *tvb)
529 {
530         int offset;
531         offset = CMPP_FIX_HEADER_LENGTH;
532         cmpp_msg_id(tree, tvb, hf_cmpp_msg_id, offset);
533         offset += 8;
534         /* TODO implement the result field here */
535         cmpp_uint4(tree, tvb, hf_cmpp_deliver_resp_Result, offset);
536 }
537
538 /* Code to actually dissect the packets */
539 static void
540 dissect_cmpp_tcp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
541 {
542
543 /* Set up structures needed to add the protocol subtree and manage it */
544         proto_item *ti;
545         proto_tree *cmpp_tree;
546         guint command_id;
547         guint tvb_len;
548         guint total_length;
549         const gchar *command_str; /* Header command string */
550
551         /* Get the length of the PDU */
552         tvb_len = tvb_length(tvb);
553         /* if the length of the tvb is shorder then the cmpp header length exit */
554         if (tvb_len < CMPP_FIX_HEADER_LENGTH)
555                 return;
556
557         total_length = tvb_get_ntohl(tvb, 0); /* Get the pdu length */
558         command_id = tvb_get_ntohl(tvb, 4); /* get the pdu command id */
559
560         if (match_strval(command_id, vals_command_Id) == NULL)
561         {
562                 /* Should never happen: we checked this in dissect_cmpp() */
563                 return;
564         }
565
566         command_str = val_to_str(command_id, vals_command_Id,
567                                  "(Unknown CMPP Operation 0x%08X)");
568
569         /* tvb has less data then the PDU Header status, return */
570         if (tvb_len < total_length)
571         {
572                 /* Should never happen: TCP should have desegmented for us */
573                 return;
574         }
575
576         /* Make entries in Protocol column and Info column on summary display */
577         col_set_str(pinfo->cinfo, COL_PROTOCOL, "CMPP");
578
579         col_append_fstr(pinfo->cinfo, COL_INFO, "%s. ", command_str);
580
581         if (tree)
582         {
583                 ti = proto_tree_add_item(tree, proto_cmpp, tvb, 0, -1, ENC_BIG_ENDIAN);
584
585                 cmpp_tree = proto_item_add_subtree(ti, ett_cmpp);
586
587                 /* Add the fix header informations to the tree */
588                 cmpp_uint4(cmpp_tree, tvb, hf_cmpp_Total_Length, 0);
589                 cmpp_uint4(cmpp_tree, tvb, hf_cmpp_Command_Id, 4);
590                 cmpp_uint4(cmpp_tree, tvb, hf_cmpp_Sequence_Id, 8);
591
592                 switch(command_id)
593                 {
594                         case CMPP_CONNECT:
595                                 cmpp_connect(cmpp_tree, tvb);
596                                 break;
597                         case CMPP_CONNECT_RESP:
598                                 cmpp_connect_resp(cmpp_tree, tvb);
599                                 break;
600                         /* CMPP_TERMINATE and CMPP_TERMINATE_RESP don't have msg body */
601                         case CMPP_TERMINATE:
602                         case CMPP_TERMINATE_RESP:
603                                 break;
604                         case CMPP_SUBMIT:
605                                 cmpp_submit(cmpp_tree, tvb);
606                                 break;
607                         case CMPP_SUBMIT_RESP:
608                                 cmpp_submit_resp(cmpp_tree, tvb);
609                                 break;
610                         case CMPP_DELIVER:
611                                 cmpp_deliver(cmpp_tree, tvb);
612                                 break;
613                         case CMPP_DELIVER_RESP:
614                                 cmpp_deliver_resp(cmpp_tree, tvb);
615                                 break;
616                         default:
617                                 /* Implement the rest of the protocol here */
618                                 break;
619                 }
620         }
621 }
622
623
624 /* Get the CMPP PDU Length */
625 static guint
626 get_cmpp_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, gint offset)
627 {
628     return tvb_get_ntohl(tvb, offset);
629 }
630
631
632 static int
633 dissect_cmpp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
634 {
635         guint total_length, command_id, tvb_len;
636         /* Check that there's enough data */
637         tvb_len = tvb_length(tvb);
638         if (tvb_len < CMPP_FIX_HEADER_LENGTH)
639                 return 0;
640
641         /* Get some values from the packet header, probably using tvb_get_*() */
642         total_length = tvb_get_ntohl(tvb, 0); /* Get the pdu length */
643         command_id = tvb_get_ntohl(tvb, 4); /* get the pdu command id */
644
645         /*  Looking at this protocol, it seems unlikely that the messages would
646          *  get as big as a couple hundred bytes but that's not certain; just
647          *  added a hopefully-way-too-big number to strengthen the heuristics.
648          */
649         if (total_length < CMPP_FIX_HEADER_LENGTH || total_length > 1000)
650                 return 0;
651
652         if (match_strval(command_id, vals_command_Id) == NULL)
653                 return 0;
654
655         col_clear(pinfo->cinfo, COL_INFO);
656
657         tcp_dissect_pdus(tvb, pinfo, tree, cmpp_desegment, CMPP_FIX_HEADER_LENGTH,
658                          get_cmpp_pdu_len, dissect_cmpp_tcp_pdu);
659
660         /* Return the amount of data this dissector was able to dissect */
661         return tvb_length(tvb);
662
663 }
664
665 /* Register the protocol with Wireshark */
666
667 /* this format is require because a script is used to build the C function
668    that calls all the protocol registration.
669 */
670 void
671 proto_register_cmpp(void) {
672
673 /* Setup list of header fields  See Section 1.6.1 for details*/
674         static hf_register_info hf[] = {
675                 { &hf_cmpp_Total_Length,
676                         { "Total Length", "cmpp.Total_Length",
677                           FT_UINT32, BASE_DEC, NULL, 0x00,
678                           "Total length of the CMPP PDU.",
679                           HFILL }
680                 },
681                 { &hf_cmpp_Command_Id,
682                         { "Command Id", "cmpp.Command_Id",
683                           FT_UINT32, BASE_HEX, VALS(vals_command_Id), 0x00,
684                           "Command Id of the CMPP messages",
685                           HFILL }
686                 },
687                 { &hf_cmpp_Sequence_Id,
688                         { "Sequence Id", "cmpp.Sequence_Id",
689                           FT_UINT32, BASE_DEC, NULL, 0x00,
690                           "Sequence Id of the CMPP messages",
691                           HFILL }
692                 },
693                 { &hf_cmpp_connect_Source_Addr,
694                         { "Source Addr", "cmpp.connect.Source_Addr",
695                           FT_STRING, BASE_NONE, NULL, 0x00,
696                           "Source Address, the SP_Id",
697                           HFILL }
698                 },
699                 { &hf_cmpp_connect_AuthenticatorSource,
700                         { "Authenticator Source", "cmpp.connect.AuthenticatorSource",
701                           FT_STRING, BASE_NONE, NULL, 0x00,
702                           "Authenticator source, MD5(Source_addr + 9 zero + shared secret + timestamp)",
703                           HFILL }
704                 },
705
706                 { &hf_cmpp_Version,
707                         { "Version", "cmpp.Version",
708                           FT_STRING, BASE_NONE, NULL, 0x00,
709                           "CMPP Version",
710                           HFILL }
711                 },
712                 { &hf_cmpp_connect_Timestamp,
713                         { "Timestamp", "cmpp.connect.Timestamp",
714                           FT_STRING, BASE_NONE, NULL, 0x00,
715                           "Timestamp MM/DD HH:MM:SS",
716                           HFILL }
717                 },
718                 { &hf_cmpp_connect_resp_status,
719                         { "Connect Response Status", "cmpp.connect_resp.Status",
720                           FT_UINT32, BASE_DEC, VALS(vals_connect_resp_status), 0x00,
721                           "Response Status, Value higher then 4 means other error",
722                           HFILL }
723                 },
724                 { &hf_cmpp_connect_resp_AuthenticatorISMG,
725                         { "SIMG Authenticate result", "cmpp.connect_resp.AuthenticatorISMG",
726                           FT_STRING, BASE_NONE, NULL, 0x00,
727                           "Authenticator result, MD5(Status + AuthenticatorSource + shared secret)",
728                           HFILL }
729                 },
730                 { &hf_cmpp_msg_id,
731                         { "Msg_Id", "cmpp.Msg_Id",
732                           FT_UINT64, BASE_HEX, NULL, 0x00,
733                           "Message ID",
734                           HFILL }
735                 },
736                 { &hf_cmpp_submit_pk_total,
737                         { "Number of Part", "cmpp.submit.Pk_total",
738                           FT_UINT8, BASE_DEC, NULL, 0x00,
739                           "Total number of parts of the message with the same Msg_Id, start from 1",
740                           HFILL }
741                 },
742                 { &hf_cmpp_submit_pk_number,
743                         { "Part Number", "cmpp.submit.Pk_number",
744                           FT_UINT8, BASE_DEC, NULL, 0x00,
745                           "Part number of the message with the same Msg_Id, start from 1",
746                           HFILL }
747                 },
748                 { &hf_msg_id_timestamp,
749                         { "Timestamp", "cmpp.Msg_Id.timestamp",
750                           FT_STRING, BASE_NONE, NULL, 0x00,
751                           "Timestamp MM/DD HH:MM:SS Bit 64 ~ 39",
752                           HFILL }
753                 },
754                 { &hf_msg_id_ismg_code,
755                         { "ISMG Code", "cmpp.Msg_Id.ismg_code",
756                           FT_UINT32, BASE_DEC, NULL, 0x00,
757                           "ISMG Code, bit 38 ~ 17",
758                           HFILL }
759                 },
760                 { &hf_msg_id_sequence_id,
761                         { "Msg_Id sequence Id", "cmpp.Msg_Id.sequence_id",
762                           FT_UINT16, BASE_DEC, NULL, 0x00,
763                           "Msg_Id sequence Id, bit 16 ~ 1",
764                           HFILL }
765                 },
766                 { &hf_cmpp_submit_Registered_Delivery,
767                         { "Registered Delivery", "cmpp.submit.Registered_Delivery",
768                           FT_BOOLEAN, BASE_NONE, NULL, 0x0,
769                           "Registered Delivery flag",
770                           HFILL }
771                 },
772                 { &hf_cmpp_submit_Msg_level,
773                         { "Message Level", "cmpp.submit.Msg_level",
774                           FT_UINT8, BASE_DEC, NULL, 0x00,
775                           NULL,
776                           HFILL }
777                 },
778                 { &hf_cmpp_Service_Id,
779                         { "Service ID", "cmpp.Servicd_Id",
780                           FT_STRING, BASE_NONE, NULL, 0x00,
781                           "Service ID, a mix of characters, numbers and symbol",
782                           HFILL }
783                 },
784                 { &hf_cmpp_submit_Fee_UserType,
785                         { "Charging Informations", "cmpp.submit.Fee_UserType",
786                           FT_UINT8, BASE_DEC, VALS(vals_submit_Fee_UserType), 0x00,
787                           "Charging Informations, if value is 3, this field will not be used",
788                           HFILL }
789                 },
790                 { &hf_cmpp_submit_Fee_terminal_Id,
791                         { "Fee Terminal ID", "cmpp.submit.Fee_terminal_Id",
792                           FT_STRING, BASE_NONE, NULL, 0x00,
793                           "Fee Terminal ID, Valid only when Fee_UserType is 3",
794                           HFILL }
795                 },
796                 { &hf_cmpp_submit_Fee_terminal_type,
797                         { "Fake Fee Terminal", "cmpp.submit.Fee_terminal_type",
798                           FT_BOOLEAN, BASE_NONE, NULL, 0x0,
799                           "Fee terminal type, 0 is real, 1 is fake",
800                           HFILL }
801                 },
802                 { &hf_cmpp_TP_pId,
803                         { "TP pId", "cmpp.TP_pId",
804                           FT_UINT8, BASE_DEC, NULL, 0x00,
805                           "GSM TP pId Field",
806                           HFILL }
807                 },
808                 { &hf_cmpp_TP_udhi,
809                         { "TP udhi", "cmpp.TP_udhi",
810                           FT_UINT8, BASE_DEC, NULL, 0x00,
811                           "GSM TP udhi field",
812                           HFILL }
813                 },
814                 { &hf_cmpp_Msg_Fmt,
815                         { "Message Format", "cmpp.Msg_Fmt",
816                           FT_UINT8, BASE_DEC, VALS(vals_Msg_Fmt), 0x00,
817                           NULL,
818                           HFILL }
819                 },
820                 { &hf_cmpp_submit_Msg_src,
821                         { "Message Source SP_Id", "cmpp.submit.Msg_src",
822                           FT_STRING, BASE_NONE, NULL, 0x00,
823                           "Message source SP ID",
824                           HFILL }
825                 },
826                 { &hf_cmpp_submit_FeeType, /* TODO Replace this with a vals_string*/
827                         { "Fee Type", "cmpp.submit.FeeType",
828                           FT_STRING, BASE_NONE, NULL, 0x00,
829                           NULL,
830                           HFILL }
831                 },
832                 { &hf_cmpp_submit_FeeCode,
833                         { "Fee Code", "cmpp.submit.FeeCode",
834                           FT_STRING, BASE_NONE, NULL, 0x00,
835                           NULL,
836                           HFILL }
837                 },
838                 { &hf_cmpp_submit_Valld_Time,
839                         { "Valid time", "cmpp.submit.Valld_Time",
840                           FT_STRING, BASE_NONE, NULL, 0x00,
841                           "Message Valid Time, format follow SMPP 3.3",
842                           HFILL }
843                 },
844                 { &hf_cmpp_submit_At_Time,
845                         { "Send time", "cmpp.submit.At_time",
846                           FT_STRING, BASE_NONE, NULL, 0x00,
847                           "Message send time, format following SMPP 3.3",
848                           HFILL }
849                 },
850                 { &hf_cmpp_submit_Src_Id,
851                         { "Source ID", "cmpp.submit.Src_Id",
852                           FT_STRING, BASE_NONE, NULL, 0x00,
853                           "This value matches SMPP submit_sm source_addr field",
854                           HFILL }
855                 },
856                 { &hf_cmpp_submit_DestUsr_tl,
857                         { "Destination Address Count", "cmpp.submit.DestUsr_tl",
858                           FT_UINT8, BASE_DEC, NULL, 0x00,
859                           "Number of destination address, must smaller then 100",
860                           HFILL }
861                 },
862                 { &hf_cmpp_Dest_terminal_Id,
863                         { "Destination Address", "cmpp.Dest_terminal_Id",
864                           FT_STRING, BASE_NONE, NULL, 0x00,
865                           "MSISDN number which receive the SMS",
866                           HFILL }
867                 },
868                 { &hf_cmpp_submit_Dest_terminal_type,
869                         { "Fake Destination Terminal", "cmpp.submit.Dest_terminal_type",
870                           FT_BOOLEAN, BASE_NONE, NULL, 0x0,
871                           "destination terminal type, 0 is real, 1 is fake",
872                           HFILL }
873                 },
874                 { &hf_cmpp_Msg_Length,
875                         { "Message length", "cmpp.Msg_Length",
876                           FT_UINT8, BASE_DEC, NULL, 0x00,
877                           "SMS Message length, ASCII must be <= 160 bytes, other must be <= 140 bytes",
878                           HFILL }
879                 },
880                 { &hf_cmpp_Msg_Content,
881                         { "Message Content", "cmpp.Msg_Content",
882                           FT_STRING, BASE_NONE, NULL, 0x00,
883                           NULL,
884                           HFILL }
885                 },
886                 { &hf_cmpp_LinkID,
887                         { "Link ID", "cmpp.LinkID",
888                           FT_STRING, BASE_NONE, NULL, 0x00,
889                           NULL,
890                           HFILL }
891                 },
892                 { &hf_cmpp_submit_resp_Result,
893                         { "Result", "cmpp.submit_resp.Result",
894                           FT_UINT32, BASE_DEC, VALS(vals_Submit_Resp_Result), 0x00,
895                           "Submit Result",
896                           HFILL }
897                 },
898                 { &hf_cmpp_deliver_Dest_Id,
899                         { "Destination ID", "cmpp.deliver.Dest_Id",
900                           FT_STRING, BASE_NONE, NULL, 0x00,
901                           "SP Service ID or server number",
902                           HFILL }
903                 },
904                 { &hf_cmpp_deliver_Src_terminal_Id,
905                         { "Src_terminal_Id", "cmpp.deliver.Src_terminal_Id",
906                           FT_STRING, BASE_NONE, NULL, 0x00,
907                           "Source MSISDN number, if it is deliver report, this will be the CMPP_SUBMIT destination number",
908                           HFILL }
909                 },
910                 { &hf_cmpp_deliver_Src_terminal_type,
911                         { "Fake source terminal type", "cmpp.deliver.Src_terminal_type",
912                           FT_BOOLEAN, BASE_NONE, NULL, 0x0,
913                           "Type of the source terminal, can be 0 (real) or 1 (fake)",
914                           HFILL }
915                 },
916                 { &hf_cmpp_deliver_Registered_Delivery,
917                         { "Deliver Report", "cmpp.deliver.Registered_Delivery",
918                           FT_BOOLEAN, BASE_NONE, NULL, 0x0,
919                           "The message is a deliver report if this value = 1",
920                           HFILL }
921                 },
922                 { &hf_cmpp_deliver_Report,
923                         { "Detail Deliver Report", "cmpp.deliver.Report",
924                           FT_NONE, BASE_NONE, NULL, 0x00,
925                           "The detail report",
926                           HFILL }
927                 },
928                 { &hf_cmpp_deliver_Report_Stat,
929                         { "Deliver Status", "cmpp.deliver.Report.Status",
930                           FT_STRING, BASE_NONE, NULL, 0x00,
931                           NULL,
932                           HFILL }
933                 },
934                 { &hf_cmpp_deliver_Report_Submit_time,
935                         { "Submit_time", "cmpp.deliver.Report.Submit_time",
936                           FT_STRING, BASE_NONE, NULL, 0x00,
937                           "Format YYMMDDHHMM",
938                           HFILL }
939                 },
940                 { &hf_cmpp_deliver_Report_Done_time,
941                         { "Done_time", "cmpp.deliver.Report.Done_time",
942                           FT_STRING, BASE_NONE, NULL, 0x00,
943                           "Format YYMMDDHHMM",
944                           HFILL }
945                 },
946                 { &hf_cmpp_deliver_Report_SMSC_sequence,
947                         { "SMSC_sequence", "cmpp.Report.SMSC_sequence",
948                           FT_UINT32, BASE_DEC, NULL, 0x00,
949                           "Sequence number",
950                           HFILL }
951                 },
952                 { &hf_cmpp_deliver_resp_Result,
953                         { "Result", "cmpp.deliver_resp.Result",
954                           FT_UINT32, BASE_DEC, VALS(vals_Deliver_Resp_Result), 0x00,
955                           "Deliver Result",
956                           HFILL }
957                 }
958         };
959
960         /* Setup protocol subtree array */
961         static gint *ett[] = {
962                 &ett_cmpp,
963                 &ett_msg_id,
964                 &ett_deliver_report,
965         };
966
967         /* Register the protocol name and description */
968         proto_cmpp = proto_register_protocol("China Mobile Point to Point Protocol",
969                                              "CMPP", "cmpp");
970
971         /* Required function calls to register the header fields and subtrees used */
972         proto_register_field_array(proto_cmpp, hf, array_length(hf));
973         proto_register_subtree_array(ett, array_length(ett));
974
975 }
976
977
978 void
979 proto_reg_handoff_cmpp(void)
980 {
981         dissector_handle_t cmpp_handle;
982
983         cmpp_handle = new_create_dissector_handle(dissect_cmpp, proto_cmpp);
984         dissector_add_uint("tcp.port", CMPP_SP_LONG_PORT, cmpp_handle);
985         dissector_add_uint("tcp.port", CMPP_SP_SHORT_PORT, cmpp_handle);
986         dissector_add_uint("tcp.port", CMPP_ISMG_LONG_PORT, cmpp_handle);
987         dissector_add_uint("tcp.port", CMPP_ISMG_SHORT_PORT, cmpp_handle);
988 }