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