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