Move 3 ASN1 dissectors to 'clean' group; move 1 PIDL dissector to 'dirty' group.
[metze/wireshark/wip.git] / epan / dissectors / packet-forces.c
1 /* packet-forces.c
2  * RFC 5810
3  * Routines for dissecting IETF ForCES protocol layer messages.Now support the following TML types:TCP+UDP,SCTP.
4  * Copyright 2009, NDSC & Zhejiang Gongshang University,Fenggen Jia <fgjia@mail.zjgsu.edu.cn or fenggen.jia@gmail.com>
5  *
6  * $Id$
7  *
8  * Wireshark - Network traffic analyzer
9  * By Gerald Combs <gerald@wireshark.org>
10  * Copyright 1998 Gerald Combs
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25  */
26
27 #include "config.h"
28
29 #include <glib.h>
30
31 #include <epan/packet.h>
32 #include <epan/prefs.h>
33 #include <epan/expert.h>
34
35 static dissector_handle_t ip_handle;
36
37 /* Initialize the ForCES protocol and registered fields */
38 static int proto_forces = -1;
39
40 /*Main header*/
41 static int hf_forces_version = -1;
42 static int hf_forces_rsvd = -1;
43 static int hf_forces_messagetype = -1;
44 static int hf_forces_sid = -1;
45 static int hf_forces_did = -1;
46 static int hf_forces_correlator = -1;
47 static int hf_forces_length = -1;
48 /*Flags*/
49 static int hf_forces_flags= -1;
50 static int hf_forces_flags_ack= -1;
51 static int hf_forces_flags_pri= -1;
52 static int hf_forces_flags_rsrvd= -1;
53 static int hf_forces_flags_em= -1;
54 static int hf_forces_flags_at= -1;
55 static int hf_forces_flags_tp= -1;
56 static int hf_forces_flags_reserved = -1;
57
58 static int hf_forces_tlv_type = -1;
59 static int hf_forces_tlv_length = -1;
60
61 /*Initiation of LFBSelect TLV*/
62 static int hf_forces_lfbselect_tlv_type_lfb_classid = -1;
63 static int hf_forces_lfbselect_tlv_type_lfb_instanceid = -1;
64
65 /*Initiation of Operation TLV*/
66 static int hf_forces_lfbselect_tlv_type_operation_type = -1;
67 static int hf_forces_lfbselect_tlv_type_operation_length = -1;
68 static int hf_forces_lfbselect_tlv_type_operation_path_type = -1;
69 static int hf_forces_lfbselect_tlv_type_operation_path_length = -1;
70 static int hf_forces_lfbselect_tlv_type_operation_path_flags = -1;
71 static int hf_forces_lfbselect_tlv_type_operation_path_flags_selector = -1;
72 static int hf_forces_lfbselect_tlv_type_operation_path_flags_reserved = -1;
73 static int hf_forces_lfbselect_tlv_type_operation_path_IDcount = -1;
74 static int hf_forces_lfbselect_tlv_type_operation_path_IDs = -1;
75 static int hf_forces_lfbselect_tlv_type_operation_path_data = -1;
76
77 /*Initiation of Redirect TLV*/
78 static int hf_forces_redirect_tlv_meta_data_tlv_type = -1;
79 static int hf_forces_redirect_tlv_meta_data_tlv_length = -1;
80 static int hf_forces_redirect_tlv_meta_data_tlv_meta_data_ilv = -1;
81 static int hf_forces_redirect_tlv_meta_data_tlv_meta_data_ilv_id = -1;
82 static int hf_forces_redirect_tlv_meta_data_tlv_meta_data_ilv_length = -1;
83 static int hf_forces_redirect_tlv_redirect_data_tlv_type = -1;
84 static int hf_forces_redirect_tlv_redirect_data_tlv_length = -1;
85
86 /*Initiation of ASResult TLV*/
87 static int hf_forces_asresult_association_setup_result = -1;
88
89 /*Initiation of ASTreason TLV*/
90 static int hf_forces_astreason_tlv_teardown_reason = -1;
91
92 /*Main TLV may be unknown*/
93 static int hf_forces_unknown_tlv = -1;
94
95 /*Message Types */
96 #define AssociationSetup            0x01
97 #define AssociationTeardown         0x02
98 #define Config                      0x03
99 #define Query                       0x04
100 #define EventNotification           0x05
101 #define PacketRedirect              0x06
102 #define Heartbeat                   0x0F
103 #define AssociationSetupRepsonse    0x11
104 #define ConfigResponse              0x13
105 #define QueryResponse               0x14
106
107 /*TLV Types*/
108 #define Reserved            0x0000
109 #define REDIRECT_TLV        0x0001
110 #define ASResult_TLV        0x0010
111 #define ASTreason_TLV       0x0011
112 #define LFBselect_TLV       0x1000
113 #define PATH_DATA_TLV       0x0110
114 #define KEYINFO_TLV         0x0111
115 #define FULLDATA_TLV        0x0112
116 #define SPARSEDATA_TLV      0x0113
117 #define RESULT_TLV          0x0114
118 #define METADATA_TLV        0x0115
119 #define REDIRECTDATA_TLV    0x0116
120
121 /*Operation Type*/
122 #define Reserved            0x0000
123 #define SET                 0x0001
124 #define SET_PROP            0x0002
125 #define SET_RESPONSE        0x0003
126 #define SET_PROP_RESPONSE   0x0004
127 #define DEL                 0x0005
128 #define DEL_RESPONSE        0x0006
129 #define GET                 0x0007
130 #define GET_PROP            0x0008
131 #define GET_RESPONSE        0x0009
132 #define GET_PROP_RESPONSE   0x000A
133 #define REPORT              0x000B
134 #define COMMIT              0x000C
135 #define COMMIT_RESPONSE     0x000D
136 #define TRCOMP              0x000E
137
138 #define FLAG_SELECTOR       0x8000
139
140 #define ForCES_HEADER_LENGTH    24
141 #define TLV_TL_LENGTH            4 /*Type+length*/
142 #define MIN_IP_HEADER_LENGTH    20
143
144 /*For TCP+UDP TML. There are two bytes added to the ForCES PL message, not strictly combine to the ForCES protocol.
145   For other type TMLs,no need to add these 2 bytes.*/
146 #define TCP_UDP_TML_FOCES_MESSAGE_OFFSET_TCP    2
147
148 /*TCP+UDP TML*/
149 static guint forces_alternate_tcp_port = 0;
150 static guint forces_alternate_udp_port = 0;
151 /*SCTP TML*/
152 static guint forces_alternate_sctp_high_prio_channel_port = 0;
153 static guint forces_alternate_sctp_med_prio_channel_port  = 0;
154 static guint forces_alternate_sctp_low_prio_channel_port  = 0;
155
156 /*Initialize the subtree pointers*/
157 static gint  ett_forces = -1;
158 static gint  ett_forces_main_header = -1;
159 static gint  ett_forces_flags = -1;
160 static gint  ett_forces_tlv = -1;
161 static gint  ett_forces_lfbselect_tlv_type = -1;
162
163 /*Operation TLV subtree*/
164 static gint  ett_forces_lfbselect_tlv_type_operation = -1;
165 static gint  ett_forces_lfbselect_tlv_type_operation_path = -1;
166 static gint  ett_forces_lfbselect_tlv_type_operation_path_data = -1;
167 static gint  ett_forces_lfbselect_tlv_type_operation_path_data_path = -1;
168 static gint  ett_forces_path_data_tlv = -1;
169 static gint  ett_forces_path_data_tlv_flags = -1;
170
171 /*Selector subtree*/
172 static gint  ett_forces_lfbselect_tlv_type_operation_path_selector = -1;
173
174 /*Redirect TLV subtree*/
175 static gint  ett_forces_redirect_tlv_type = -1;
176 static gint  ett_forces_redirect_tlv_meta_data_tlv = -1;
177 static gint  ett_forces_redirect_tlv_meta_data_tlv_meta_data_ilv = -1;
178 static gint  ett_forces_redirect_tlv_redirect_data_tlv = -1;
179
180 /*ASResult TLV subtree*/
181 static gint  ett_forces_asresult_tlv = -1;
182
183 /*ASReason subtree*/
184 static gint  ett_forces_astreason_tlv = -1;
185
186 /*Main_TLV unknown subtree*/
187 static gint  ett_forces_unknown_tlv = -1;
188
189 /*ACK values and the strings to be displayed*/
190 static const value_string main_header_flags_ack_vals[] = {
191     { 0x0, "NoACK" },
192     { 0x1, "SuccessACK" },
193     { 0x2, "FailureACK" },
194     { 0x3, "AlwaysACK" },
195     { 0, NULL}
196 };
197
198 /*Execution mode(EM) values and the strings to be displayed*/
199 static const value_string main_header_flags_em_vals[] = {
200     { 0x0, "Reserved" },
201     { 0x1, "Execute-all-or-none" },
202     { 0x2, "Execute-until-failure" },
203     { 0x3, "Continue-execute-on-failure" },
204     { 0, NULL}
205 };
206
207 /*Transaction Phase values and the strings to be displayed*/
208 static const value_string main_header_flags_tp_vals[] = {
209     { 0x0, "SOT (Start of Transaction)" },
210     { 0x1, "MOT (Middle of Transaction)" },
211     { 0x2, "EOT (End of Transaction)" },
212     { 0x3, "ABT (Abort)" },
213     { 0, NULL}
214 };
215
216 /*Atomic Transaction(AT) values and the strings to be displayed*/
217 static const value_string main_header_flags_at_vals[] = {
218     { 0x0, "Stand-alone Message"},
219     { 0x1, "2PC Transaction Message"},
220     { 0, NULL}
221 };
222
223 /*Association Setup Result*/
224 static const value_string association_setup_result_at_vals[] = {
225     { 0x0, "success"},
226     { 0x1, "FE ID invalid"},
227     { 0x2, "permission denied"},
228     { 0, NULL},
229 };
230
231 /*Teardown Reason*/
232 static const value_string teardown_reason_at_vals[] = {
233     { 0x0,   "normal-teardown by administrator"},
234     { 0x1,   "error - loss of heartbeats"},
235     { 0x2,   "error - out of bandwidth"},
236     { 0x3,   "error - out of memory"},
237     { 0x4,   "error - application crash"},
238     { 0x255, "error - other or unspecified"},
239     { 0,     NULL},
240 };
241
242 static const value_string message_type_vals[] = {
243     { AssociationSetup,         "AssociationSetup" },
244     { AssociationTeardown,      "AssociationTeardown" },
245     { Config,                   "Config" },
246     { Query,                    "Query" },
247     { EventNotification,        "EventNotification" },
248     { PacketRedirect,           "PacketRedirect" },
249     { Heartbeat,                "Heartbeat" },
250     { AssociationSetupRepsonse, "AssociationSetupRepsonse" },
251     { ConfigResponse,           "ConfigResponse" },
252     { QueryResponse,            "QueryResponse" },
253     { 0,                        NULL},
254 };
255
256 static const value_string tlv_type_vals[] = {
257     { REDIRECT_TLV,     "REDIRECT-TLV" },
258     { ASResult_TLV,     "ASResult-TLV" },
259     { ASTreason_TLV,    "ASTreason-TLV" },
260     { LFBselect_TLV,    "LFBselect-TLV" },
261     { PATH_DATA_TLV,    "PATH DATA-TLV" },
262     { KEYINFO_TLV,      "KEYINFO-TLV" },
263     { FULLDATA_TLV,     "FULLDATA-TLV" },
264     { SPARSEDATA_TLV,   "SPARSEDATA-TLV" },
265     { RESULT_TLV,       "RESULT-TLV" },
266     { METADATA_TLV,     "METADATA-TLV" },
267     { REDIRECTDATA_TLV, "REDIRECTDATA-TLV" },
268     { 0,                NULL},
269 };
270
271 static const value_string operation_type_vals[] = {
272     { Reserved,          "Reserved" },
273     { SET,               "SET" },
274     { SET_PROP,          "SET-PROP" },
275     { SET_RESPONSE,      "SET-RESPONSE" },
276     { SET_PROP_RESPONSE, "SET-PROP-RESPONSE" },
277     { DEL,               "DEL" },
278     { DEL_RESPONSE,      "DEL-RESPONSE" },
279     { GET,               "GET" },
280     { GET_PROP,          "GET-PROP" },
281     { GET_RESPONSE,      "GET-RESPONSE" },
282     { GET_PROP_RESPONSE, "GET-PROP-RESPONSE" },
283     { REPORT,            "REPORT" },
284     { COMMIT,            "COMMIT" },
285     { COMMIT_RESPONSE,   "COMMIT-RESPONSE" },
286     { TRCOMP,            "TRCOMP" },
287     { 0,                 NULL},
288 };
289
290 static void
291 dissect_path_data_tlv(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
292 {
293     proto_item *ti, *flag_item;
294     guint       length_TLV, IDcount, i;
295     guint16     type, flag;
296     proto_tree *tlv_tree, *path_data_tree, *flag_tree;
297
298     while (tvb_reported_length_remaining(tvb, offset) >= TLV_TL_LENGTH)
299     {
300         ti = proto_tree_add_text(tree, tvb, offset, TLV_TL_LENGTH, "TLV");
301         tlv_tree = proto_item_add_subtree(ti, ett_forces_path_data_tlv);
302
303         type = tvb_get_ntohs(tvb, offset);
304         proto_tree_add_item(tlv_tree, hf_forces_lfbselect_tlv_type_operation_path_type,
305                             tvb, offset, 2, ENC_BIG_ENDIAN);
306         length_TLV = tvb_get_ntohs(tvb, offset+2);
307         proto_tree_add_item(tlv_tree, hf_forces_lfbselect_tlv_type_operation_path_length,
308                             tvb, offset+2, 2, ENC_BIG_ENDIAN);
309         if (length_TLV < TLV_TL_LENGTH)
310         {
311             expert_add_info_format(pinfo, ti, PI_PROTOCOL, PI_WARN, "Bogus TLV length: %u", length_TLV);
312             break;
313         }
314         proto_item_set_len(ti, length_TLV);
315
316         if (type == PATH_DATA_TLV)
317         {
318             ti = proto_tree_add_text(tree, tvb, offset+TLV_TL_LENGTH, length_TLV-TLV_TL_LENGTH, "Path Data TLV");
319             path_data_tree = proto_item_add_subtree(ti, ett_forces_path_data_tlv);
320
321             flag = tvb_get_ntohs(tvb, offset+TLV_TL_LENGTH);
322             flag_item = proto_tree_add_item(path_data_tree, hf_forces_lfbselect_tlv_type_operation_path_flags,
323                                 tvb, offset+TLV_TL_LENGTH, 2, ENC_BIG_ENDIAN);
324             flag_tree = proto_item_add_subtree(flag_item, ett_forces_path_data_tlv_flags);
325             proto_tree_add_item(flag_tree, hf_forces_lfbselect_tlv_type_operation_path_flags_selector,
326                                 tvb, offset+TLV_TL_LENGTH, 2, ENC_BIG_ENDIAN);
327             proto_tree_add_item(flag_tree, hf_forces_lfbselect_tlv_type_operation_path_flags_reserved,
328                                 tvb, offset+TLV_TL_LENGTH, 2, ENC_BIG_ENDIAN);
329
330             IDcount = tvb_get_ntohs(tvb, offset + TLV_TL_LENGTH + 2);
331             proto_tree_add_item(path_data_tree, hf_forces_lfbselect_tlv_type_operation_path_IDcount,
332                                 tvb, offset+TLV_TL_LENGTH+2, 2, ENC_BIG_ENDIAN);
333
334             for (i = 0; i < IDcount; i++)
335                 proto_tree_add_item(path_data_tree, hf_forces_lfbselect_tlv_type_operation_path_IDs,
336                                     tvb, offset+TLV_TL_LENGTH+2+(i*4), 4, ENC_BIG_ENDIAN);
337         }
338         else
339         {
340             flag = 0;
341             proto_tree_add_item(tree, hf_forces_lfbselect_tlv_type_operation_path_data,
342                                 tvb, offset+TLV_TL_LENGTH, length_TLV-TLV_TL_LENGTH, ENC_NA);
343         }
344
345         if ((flag & FLAG_SELECTOR) == 0)
346             break;
347
348         offset += length_TLV;
349     }
350 }
351
352 static void
353 dissect_operation_tlv(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset, gint length_count)
354 {
355     proto_item *ti;
356     proto_tree *oper_tree;
357     guint       type, length;
358
359     while (tvb_reported_length_remaining(tvb, offset) >= TLV_TL_LENGTH)
360     {
361         ti = proto_tree_add_text(tree, tvb, offset, length_count, "Operation TLV");
362         oper_tree = proto_item_add_subtree(ti, ett_forces_lfbselect_tlv_type_operation);
363
364         type = tvb_get_ntohs(tvb,offset);
365         ti = proto_tree_add_item(oper_tree, hf_forces_lfbselect_tlv_type_operation_type,
366                                  tvb, offset, 2, ENC_BIG_ENDIAN);
367         if (match_strval(type, operation_type_vals) == NULL)
368             expert_add_info_format(pinfo, ti, PI_PROTOCOL, PI_WARN,
369                 "Bogus: ForCES Operation TLV (Type:0x%04x) is not supported", type);
370
371         length = tvb_get_ntohs(tvb, offset+2);
372         proto_tree_add_uint_format(oper_tree, hf_forces_lfbselect_tlv_type_operation_length,
373                                    tvb, offset+2, 2, length, "Length: %u Bytes", length);
374
375         dissect_path_data_tlv(tvb, pinfo, oper_tree, offset+TLV_TL_LENGTH);
376         if (length == 0)
377             break;
378         offset += length;
379     }
380 }
381
382 static void
383 dissect_lfbselecttlv(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset, gint length_count)
384 {
385     guint tlv_length;
386
387     proto_tree_add_item(tree, hf_forces_lfbselect_tlv_type_lfb_classid,    tvb, offset,   4, ENC_BIG_ENDIAN);
388     proto_tree_add_item(tree, hf_forces_lfbselect_tlv_type_lfb_instanceid, tvb, offset+4, 4, ENC_BIG_ENDIAN);
389
390     offset += 8;
391     while ((tvb_reported_length_remaining(tvb, offset) > TLV_TL_LENGTH) && (length_count > 12))
392     {
393         tlv_length = tvb_get_ntohs(tvb, offset+2);
394         dissect_operation_tlv(tvb, pinfo, tree, offset, tlv_length);
395         if (tlv_length == 0)
396             break;
397         offset += tlv_length;
398     }
399 }
400
401 static void
402 dissect_redirecttlv(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
403 {
404     proto_tree *meta_data_tree, *meta_data_ilv_tree, *redirect_data_tree;
405     gint        start_offset;
406     gint        length_meta, length_ilv, length_redirect;
407     proto_item *ti;
408     address     src_addr     = pinfo->src,
409                 src_net_addr = pinfo->net_src,
410                 dst_addr     = pinfo->dst,
411                 dst_net_addr = pinfo->net_dst;
412
413     ti = proto_tree_add_text(tree, tvb, offset, TLV_TL_LENGTH, "Meta Data TLV");
414     meta_data_tree = proto_item_add_subtree(ti, ett_forces_redirect_tlv_meta_data_tlv);
415     proto_tree_add_item(meta_data_tree, hf_forces_redirect_tlv_meta_data_tlv_type, tvb, offset, 2, ENC_BIG_ENDIAN);
416
417     length_meta = tvb_get_ntohs(tvb, offset+2);
418     proto_tree_add_uint_format(meta_data_tree, hf_forces_redirect_tlv_meta_data_tlv_length, tvb, offset+2, 2,
419                                length_meta, "Length: %u Bytes", length_meta);
420     proto_item_set_len(ti, length_meta);
421
422     start_offset = offset;
423     while ((tvb_reported_length_remaining(tvb, offset) >= 8) && (start_offset+length_meta > offset))
424     {
425         ti = proto_tree_add_text(tree, tvb, offset, TLV_TL_LENGTH, "Meta Data ILV");
426         meta_data_ilv_tree =  proto_item_add_subtree(ti, ett_forces_redirect_tlv_meta_data_tlv_meta_data_ilv);
427
428         proto_tree_add_item(meta_data_ilv_tree, hf_forces_redirect_tlv_meta_data_tlv_meta_data_ilv_id,
429                                    tvb, offset+8, 4, ENC_BIG_ENDIAN);
430         length_ilv = tvb_get_ntohl(tvb, offset+12);
431         proto_tree_add_uint_format(meta_data_ilv_tree, hf_forces_redirect_tlv_meta_data_tlv_meta_data_ilv_length,
432                                    tvb,  offset+12, 4, length_ilv, "Length: %u Bytes", length_ilv);
433         if (length_ilv > 0)
434             proto_tree_add_item(meta_data_ilv_tree, hf_forces_redirect_tlv_meta_data_tlv_meta_data_ilv,
435                                    tvb, offset+8, length_ilv, ENC_NA);
436
437         proto_item_set_len(ti, length_ilv + 8);
438         offset += length_ilv + 8;
439     }
440
441     if (tvb_reported_length_remaining(tvb, offset) > 0)
442     {
443         ti = proto_tree_add_text(tree, tvb, offset, TLV_TL_LENGTH, "Redirect Data TLV");
444         redirect_data_tree = proto_item_add_subtree(ti, ett_forces_redirect_tlv_redirect_data_tlv);
445
446         proto_tree_add_item(redirect_data_tree, hf_forces_redirect_tlv_redirect_data_tlv_type,
447                             tvb, offset, 2,  ENC_BIG_ENDIAN);
448         length_redirect = tvb_get_ntohs(tvb, offset+2);
449         proto_tree_add_uint_format(redirect_data_tree, hf_forces_redirect_tlv_redirect_data_tlv_length,
450                             tvb, offset+2, 2, length_redirect, "Length: %u Bytes", length_redirect);
451
452         if (tvb_reported_length_remaining(tvb, offset) < length_redirect)
453         {
454             expert_add_info_format(pinfo, ti, PI_PROTOCOL, PI_WARN,
455                 "Bogus: Redirect Data TLV length (%u bytes) is wrong", length_redirect);
456         }
457         else if (length_redirect < TLV_TL_LENGTH + MIN_IP_HEADER_LENGTH)
458         {
459             expert_add_info_format(pinfo, ti, PI_PROTOCOL, PI_WARN,
460                 "Bogus: Redirect Data TLV length (%u bytes) not big enough for IP layer", length_redirect);
461         }
462         else
463         {
464             tvbuff_t  *next_tvb;
465
466             next_tvb = tvb_new_subset(tvb, offset+4, length_redirect-TLV_TL_LENGTH, length_redirect-TLV_TL_LENGTH);
467             call_dissector(ip_handle, next_tvb, pinfo, redirect_data_tree);
468
469             /* Restore IP info */
470             memcpy(&(pinfo->src),     &src_addr,     sizeof(address));
471             memcpy(&(pinfo->net_src), &src_net_addr, sizeof(address));
472             memcpy(&(pinfo->dst),     &dst_addr,     sizeof(address));
473             memcpy(&(pinfo->net_dst), &dst_net_addr, sizeof(address));
474         }
475     }
476 }
477
478 static void
479 dissect_forces(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset)
480 {
481     /* Set up structures needed to add the protocol subtree and manage it */
482     proto_item *ti, *tlv_item;
483     proto_tree *forces_tree, *forces_flags_tree;
484     proto_tree *forces_main_header_tree, *forces_tlv_tree, *tlv_tree;
485     gint        length_count;
486
487     guint8      message_type;
488     guint16     tlv_type;
489
490     /* Make entries in Protocol column and Info column on summary display */
491     col_set_str(pinfo->cinfo, COL_PROTOCOL, "ForCES");
492     col_clear(pinfo->cinfo, COL_INFO);
493
494     ti = proto_tree_add_item(tree, proto_forces, tvb, 0, -1, ENC_NA);
495     forces_tree = proto_item_add_subtree(ti, ett_forces);
496
497     ti = proto_tree_add_text(forces_tree, tvb, 0, ForCES_HEADER_LENGTH, "Common Header");
498     forces_main_header_tree = proto_item_add_subtree(ti, ett_forces_main_header);
499
500     proto_tree_add_item(forces_main_header_tree, hf_forces_version, tvb, 0, 1, ENC_BIG_ENDIAN);
501     proto_tree_add_item(forces_main_header_tree, hf_forces_rsvd,    tvb, 0, 1, ENC_BIG_ENDIAN);
502
503     message_type = tvb_get_guint8(tvb, offset+1);
504     proto_tree_add_item( forces_main_header_tree, hf_forces_messagetype, tvb, offset+1, 1, ENC_BIG_ENDIAN);
505
506     length_count = tvb_get_ntohs(tvb, offset+2) * 4;  /*multiply 4 DWORD*/
507     ti = proto_tree_add_uint_format( forces_main_header_tree, hf_forces_length,
508                                      tvb, offset+2, 2, length_count, "Length: %u Bytes", length_count);
509     if (length_count != tvb_reported_length_remaining(tvb, offset))
510         expert_add_info_format(pinfo, ti, PI_PROTOCOL, PI_WARN,
511             "Bogus: ForCES Header length (%u bytes) is wrong),should be (%u bytes)",
512             length_count, tvb_reported_length_remaining(tvb, offset));
513     if (length_count < 24)
514         expert_add_info_format(pinfo, ti, PI_PROTOCOL, PI_WARN,
515             "Bogus: ForCES Header length (%u bytes) is less than 24bytes)", length_count);
516
517     col_add_fstr(pinfo->cinfo, COL_INFO, "Message Type: %s, Total Length:  %u Bytes",
518             val_to_str(message_type, message_type_vals, "Unknown messagetype 0x%x"), length_count);
519
520     proto_tree_add_item( forces_main_header_tree, hf_forces_sid,        tvb, offset+4,  4, ENC_BIG_ENDIAN);
521     proto_tree_add_item( forces_main_header_tree, hf_forces_did,        tvb, offset+8,  4, ENC_BIG_ENDIAN);
522     proto_tree_add_item( forces_main_header_tree, hf_forces_correlator, tvb, offset+12, 8, ENC_BIG_ENDIAN);
523
524     /*Add flags tree*/
525     ti = proto_tree_add_item(forces_main_header_tree, hf_forces_flags, tvb, offset+20, 4, ENC_BIG_ENDIAN);
526     forces_flags_tree = proto_item_add_subtree(ti, ett_forces_flags);
527
528     proto_tree_add_item(forces_flags_tree, hf_forces_flags_ack,      tvb, offset+20, 4, ENC_BIG_ENDIAN);
529     proto_tree_add_item(forces_flags_tree, hf_forces_flags_at,       tvb, offset+20, 4, ENC_BIG_ENDIAN);
530     proto_tree_add_item(forces_flags_tree, hf_forces_flags_em,       tvb, offset+20, 4, ENC_BIG_ENDIAN);
531     proto_tree_add_item(forces_flags_tree, hf_forces_flags_pri,      tvb, offset+20, 4, ENC_BIG_ENDIAN);
532     proto_tree_add_item(forces_flags_tree, hf_forces_flags_reserved, tvb, offset+20, 4, ENC_BIG_ENDIAN);
533     proto_tree_add_item(forces_flags_tree, hf_forces_flags_rsrvd,    tvb, offset+20, 4, ENC_BIG_ENDIAN);
534     proto_tree_add_item(forces_flags_tree, hf_forces_flags_tp,       tvb, offset+20, 4, ENC_BIG_ENDIAN);
535
536     offset += 24;
537     while (tvb_reported_length_remaining(tvb, offset) >= TLV_TL_LENGTH)
538     {
539         ti = proto_tree_add_text(forces_tree, tvb, offset, TLV_TL_LENGTH, "TLV");
540         forces_tlv_tree = proto_item_add_subtree(ti, ett_forces_tlv);
541
542         tlv_type = tvb_get_ntohs(tvb, offset);
543         tlv_item = proto_tree_add_item(forces_tlv_tree, hf_forces_tlv_type, tvb, offset, 2, ENC_BIG_ENDIAN);
544         length_count = tvb_get_ntohs(tvb, offset+2) * 4;
545         proto_item_set_len(ti, length_count);
546         ti = proto_tree_add_uint_format(forces_tlv_tree, hf_forces_tlv_length,
547                                         tvb, offset+2, 2, length_count, "Length: %u Bytes", length_count);
548         if (tvb_reported_length_remaining(tvb, offset) < length_count)
549             expert_add_info_format(pinfo, ti, PI_PROTOCOL, PI_WARN,
550                 "Bogus: Main TLV length (%u bytes) is wrong", length_count);
551
552         if (length_count < TLV_TL_LENGTH)
553         {
554             expert_add_info_format(pinfo, ti, PI_PROTOCOL, PI_WARN, "Bogus TLV length: %u", length_count);
555             break;
556         }
557
558         offset       += TLV_TL_LENGTH;
559         length_count -= TLV_TL_LENGTH;
560
561         switch(tlv_type)
562         {
563         case LFBselect_TLV:
564             ti = proto_tree_add_text(forces_tlv_tree, tvb, offset, length_count, "LFB select TLV");
565             tlv_tree = proto_item_add_subtree(ti, ett_forces_lfbselect_tlv_type);
566             dissect_lfbselecttlv(tvb, pinfo, tlv_tree, offset, length_count);
567             break;
568
569         case REDIRECT_TLV:
570             ti = proto_tree_add_text(forces_tlv_tree, tvb, offset, length_count, "Redirect TLV");
571             tlv_tree = proto_item_add_subtree(ti, ett_forces_redirect_tlv_type);
572             dissect_redirecttlv(tvb, pinfo, tlv_tree, offset);
573             break;
574
575         case ASResult_TLV:
576             ti = proto_tree_add_text(forces_tlv_tree, tvb, offset, length_count, "ASResult TLV");
577             tlv_tree = proto_item_add_subtree(ti, ett_forces_asresult_tlv);
578             proto_tree_add_item(tlv_tree, hf_forces_asresult_association_setup_result, tvb, offset, 4, ENC_BIG_ENDIAN);
579             break;
580
581         case ASTreason_TLV:
582             ti = proto_tree_add_text(forces_tlv_tree, tvb, offset, length_count, "ASTreason TLV");
583             tlv_tree = proto_item_add_subtree(ti, ett_forces_astreason_tlv);
584             proto_tree_add_item(tlv_tree, hf_forces_astreason_tlv_teardown_reason, tvb, offset, 4, ENC_BIG_ENDIAN);
585             break;
586
587         default:
588             expert_add_info_format(pinfo, tlv_item, PI_PROTOCOL, PI_WARN,
589                 "Bogus: The Main_TLV type is unknown");
590             ti = proto_tree_add_text(forces_tlv_tree, tvb, offset, length_count, "Unknown TLV");
591             tlv_tree = proto_item_add_subtree(ti, ett_forces_unknown_tlv);
592             proto_tree_add_item(tlv_tree, hf_forces_unknown_tlv, tvb, offset, length_count, ENC_NA);
593             break;
594         }
595
596         offset += length_count;
597     }
598 }
599
600 /* Code to actually dissect the TCP packets */
601 static void
602 dissect_forces_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
603 {
604     dissect_forces(tvb, pinfo, tree, TCP_UDP_TML_FOCES_MESSAGE_OFFSET_TCP);
605 }
606
607 /* Code to actually dissect the ForCES protocol layer packets,like UDP,SCTP and others */
608 static void
609 dissect_forces_not_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
610 {
611     dissect_forces(tvb, pinfo, tree, 0);
612 }
613
614 void proto_reg_handoff_forces(void);
615
616 void
617 proto_register_forces(void)
618 {
619     module_t *forces_module;
620
621     /* Setup list of header fields  See Section 1.6.1 for details*/
622     static hf_register_info hf[] = {
623         { &hf_forces_version,
624             { "Version", "forces.flags.version",
625             FT_UINT8, BASE_DEC, NULL, 0xF0, NULL, HFILL }
626         },
627         { &hf_forces_rsvd,
628             { "Rsvd", "forces.flags.rsvd",
629             FT_UINT8, BASE_DEC, NULL, 0x0F, NULL, HFILL }
630         },
631         { &hf_forces_messagetype,
632             { "Message Type", "forces.messagetype",
633             FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }
634         },
635         { &hf_forces_length,
636             { "Header Length", "forces.length",
637             FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
638         },
639         { &hf_forces_sid,
640             { "Source ID", "forces.sid",
641             FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL }
642         },
643         { &hf_forces_did,
644             { "Destination ID", "forces.did",
645             FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL }
646         },
647         { &hf_forces_correlator,
648             { "Correlator", "forces.correlator",
649             FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL }
650         },
651         { &hf_forces_tlv_type,
652             { "Type", "forces.tlv.type",
653             FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
654         },
655         { &hf_forces_tlv_length,
656             { "Length", "forces.tlv.length",
657             FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
658         },
659         /*flags*/
660         { &hf_forces_flags,
661             { "Flags", "forces.Flags",
662             FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
663         },
664         { &hf_forces_flags_ack,
665             { "ACK indicator", "forces.flags.ack",
666             FT_UINT32, BASE_DEC, VALS(main_header_flags_ack_vals), 0xC0000000, NULL, HFILL }
667         },
668         { &hf_forces_flags_pri,
669             { "Priority", "forces.flags.pri",
670             FT_UINT32, BASE_DEC, NULL, 0x38000000, NULL, HFILL }
671         },
672         { &hf_forces_flags_rsrvd,
673             { "Rsrvd", "forces.Flags",
674             FT_UINT32, BASE_DEC,NULL, 0x07000000, NULL, HFILL }
675         },
676         { &hf_forces_flags_em,
677             { "Execution mode", "forces.flags.em",
678             FT_UINT32, BASE_DEC, VALS(main_header_flags_em_vals), 0x00C00000, NULL, HFILL }
679         },
680         { &hf_forces_flags_at,
681             { "Atomic Transaction", "forces.flags.at",
682             FT_UINT32, BASE_DEC, VALS(main_header_flags_at_vals), 0x00200000, NULL, HFILL }
683         },
684         { &hf_forces_flags_tp,
685             { "Transaction phase", "forces.flags.tp",
686             FT_UINT32, BASE_DEC, VALS(main_header_flags_tp_vals), 0x00180000, NULL, HFILL }
687         },
688         { &hf_forces_flags_reserved,
689             { "Reserved", "forces.flags.reserved",
690             FT_UINT32, BASE_DEC,NULL, 0x0007ffff, NULL, HFILL }
691         },
692         /*LFBSelectTLV*/
693         { &hf_forces_lfbselect_tlv_type_lfb_classid,
694             { "Class ID", "forces.lfbselect.tlv.type.lfb.classid",
695             FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL }
696         },
697         { &hf_forces_lfbselect_tlv_type_lfb_instanceid,
698             { "Instance ID", "forces.fbselect.tlv.type.lfb.instanceid",
699             FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL }
700         },
701         /*Operation TLV*/
702         { &hf_forces_lfbselect_tlv_type_operation_type,
703             { "Type", "forces.lfbselect.tlv.type.operation.type",
704             FT_UINT16, BASE_DEC, VALS(operation_type_vals), 0x0, NULL, HFILL }
705         },
706         { &hf_forces_lfbselect_tlv_type_operation_length,
707             { "Length", "forces.lfbselect.tlv.type.operation.length",
708             FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
709         },
710         { &hf_forces_lfbselect_tlv_type_operation_path_type,
711             { "Type", "forces.lfbselect.tlv.type.operation.path.type",
712             FT_UINT16, BASE_DEC, VALS(tlv_type_vals), 0x0, NULL, HFILL }
713         },
714         { &hf_forces_lfbselect_tlv_type_operation_path_length,
715             { "Length", "forces.lfbselect.tlv.type.operation.path.length",
716             FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
717         },
718         { &hf_forces_lfbselect_tlv_type_operation_path_data,
719             { "Data", "forces.lfbselect.tlv.type.operation.path.data",
720             FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }
721         },
722         { &hf_forces_lfbselect_tlv_type_operation_path_flags,
723             {"Path Data Flags", "forces.lfbselect.tlv.type.operation.path.data.flags",
724             FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }
725         },
726         { &hf_forces_lfbselect_tlv_type_operation_path_flags_selector,
727             {"Selector", "forces.lfbselect.tlv.type.operation.path.data.flags.selector",
728             FT_UINT16, BASE_HEX, NULL, 0x80, NULL, HFILL }
729         },
730         { &hf_forces_lfbselect_tlv_type_operation_path_flags_reserved,
731             {"Reserved", "forces.lfbselect.tlv.type.operation.path.data.flags.reserved",
732             FT_UINT16, BASE_HEX, NULL, 0x7F, NULL, HFILL }
733         },
734         { &hf_forces_lfbselect_tlv_type_operation_path_IDcount,
735             { "Path Data IDcount", "forces.lfbselect.tlv.type.operation.path.data.IDcount",
736             FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
737         },
738         { &hf_forces_lfbselect_tlv_type_operation_path_IDs,
739             { "Path Data IDs", "forces.lfbselect.tlv.type.operation.path.data.IDs",
740             FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
741         },
742         /*Meta data TLV*/
743         {&hf_forces_redirect_tlv_meta_data_tlv_type,
744             { "Type", "forces.redirect.tlv.meta.data.tlv.type",
745             FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
746         },
747         { &hf_forces_redirect_tlv_meta_data_tlv_length,
748             { "Length", "forces.redirect.tlv.meta.data.tlv.length",
749             FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
750         },
751         { &hf_forces_redirect_tlv_meta_data_tlv_meta_data_ilv,
752             { "Meta Data ILV", "forces.redirect.tlv.meta.data.tlv.meta.data.ilv",
753             FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }
754         },
755         { &hf_forces_redirect_tlv_meta_data_tlv_meta_data_ilv_id,
756             { "ID", "forces.redirect.tlv.meta.data.tlv.meta.data.ilv.id",
757             FT_UINT32, BASE_HEX_DEC, NULL, 0x0, NULL, HFILL }
758         },
759         { &hf_forces_redirect_tlv_meta_data_tlv_meta_data_ilv_length,
760             { "Length", "forces.redirect.tlv.meta.data.tlv.meta.data.ilv.length",
761             FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
762         },
763         { &hf_forces_redirect_tlv_redirect_data_tlv_type,
764             { "Type", "forces.redirect.tlv.redirect.data.tlv.type",
765             FT_UINT16, BASE_DEC, VALS(tlv_type_vals), 0x0, NULL, HFILL }
766         },
767         { &hf_forces_redirect_tlv_redirect_data_tlv_length,
768             { "Length", "forces.redirect.tlv.redirect.data.tlv.length",
769             FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
770         },
771         { &hf_forces_asresult_association_setup_result,
772             { "Association Setup Result", "forces.teardown.reason",
773             FT_UINT32, BASE_DEC, VALS(association_setup_result_at_vals), 0x0, NULL, HFILL }
774         },
775         { &hf_forces_astreason_tlv_teardown_reason,
776             { "AStreason TLV TearDonw Reason", "forces.astreason.tlv.teardonw.reason",
777             FT_UINT32, BASE_DEC, VALS(teardown_reason_at_vals), 0x0, NULL, HFILL }
778         },
779         { &hf_forces_unknown_tlv,
780             { "Data", "forces.unknown.tlv",
781             FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }
782         }
783     };
784
785     /* Setup protocol subtree array */
786     static gint *ett[] = {
787         &ett_forces,
788         &ett_forces_main_header,
789         &ett_forces_flags,
790         &ett_forces_tlv,
791         &ett_forces_lfbselect_tlv_type,
792         &ett_forces_lfbselect_tlv_type_operation,
793         &ett_forces_lfbselect_tlv_type_operation_path,
794         &ett_forces_lfbselect_tlv_type_operation_path_data,
795         &ett_forces_lfbselect_tlv_type_operation_path_data_path,
796         &ett_forces_lfbselect_tlv_type_operation_path_selector,
797         &ett_forces_path_data_tlv,
798         &ett_forces_path_data_tlv_flags,
799         &ett_forces_redirect_tlv_type,
800         &ett_forces_redirect_tlv_meta_data_tlv,
801         &ett_forces_redirect_tlv_redirect_data_tlv,
802         &ett_forces_redirect_tlv_meta_data_tlv_meta_data_ilv,
803         &ett_forces_asresult_tlv,
804         &ett_forces_astreason_tlv,
805         &ett_forces_unknown_tlv
806     };
807
808     /* Register the protocol name and description */
809     proto_forces = proto_register_protocol("Forwarding and Control Element Separation Protocol", "ForCES", "forces");
810
811     /* Required function calls to register the header fields and subtrees used */
812     proto_register_field_array(proto_forces, hf, array_length(hf));
813     proto_register_subtree_array(ett, array_length(ett));
814
815     forces_module = prefs_register_protocol(proto_forces,proto_reg_handoff_forces);
816
817     prefs_register_uint_preference(forces_module, "tcp_alternate_port",
818                                    "TCP port",
819                                    "Decode packets on this TCP port as ForCES",
820                                    10, &forces_alternate_tcp_port);
821
822     prefs_register_uint_preference(forces_module, "udp_alternate_port",
823                                    "UDP port",
824                                    "Decode packets on this UDP port as ForCES",
825                                    10, &forces_alternate_udp_port);
826
827     prefs_register_uint_preference(forces_module, "sctp_high_prio_port",
828                                    "SCTP High Priority channel port",
829                                    "Decode packets on this sctp port as ForCES",
830                                    10, &forces_alternate_sctp_high_prio_channel_port);
831
832     prefs_register_uint_preference(forces_module, "sctp_med_prio_port",
833                                    "SCTP Meidium Priority channel port",
834                                    "Decode packets on this sctp port as ForCES",
835                                    10, &forces_alternate_sctp_med_prio_channel_port);
836
837     prefs_register_uint_preference(forces_module, "sctp_low_prio_port",
838                                    "SCTP Low Priority channel port",
839                                    "Decode packets on this sctp port as ForCES",
840                                    10, &forces_alternate_sctp_low_prio_channel_port);
841 }
842
843 void
844 proto_reg_handoff_forces(void)
845 {
846     static gboolean inited = FALSE;
847
848     static guint alternate_tcp_port = 0; /* 3000 */
849     static guint alternate_udp_port = 0;
850     static guint alternate_sctp_high_prio_channel_port = 0; /* 6700 */
851     static guint alternate_sctp_med_prio_channel_port  = 0;
852     static guint alternate_sctp_low_prio_channel_port  = 0;
853
854     static dissector_handle_t  forces_handle_tcp, forces_handle;
855
856     if (!inited) {
857         forces_handle_tcp = create_dissector_handle(dissect_forces_tcp,     proto_forces);
858         forces_handle     = create_dissector_handle(dissect_forces_not_tcp, proto_forces);
859         ip_handle = find_dissector("ip");
860         inited = TRUE;
861     }
862
863     /* Register TCP port for dissection */
864     if ((alternate_tcp_port != 0) && (alternate_tcp_port != forces_alternate_tcp_port))
865         dissector_delete_uint("tcp.port", alternate_tcp_port, forces_handle_tcp);
866     if ((forces_alternate_tcp_port != 0) && (alternate_tcp_port != forces_alternate_tcp_port))
867         dissector_add_uint("tcp.port", forces_alternate_tcp_port, forces_handle_tcp);
868     alternate_tcp_port = forces_alternate_tcp_port;
869
870     /* Register UDP port for dissection */
871     if ((alternate_udp_port != 0) && (alternate_udp_port != forces_alternate_udp_port))
872         dissector_delete_uint("udp.port", alternate_udp_port, forces_handle);
873     if ((forces_alternate_udp_port != 0) && (alternate_udp_port != forces_alternate_udp_port))
874         dissector_add_uint("udp.port", forces_alternate_udp_port, forces_handle);
875     alternate_udp_port = forces_alternate_udp_port;
876
877     /* Register SCTP port for high priority dissection */
878     if ((alternate_sctp_high_prio_channel_port != 0) &&
879         (alternate_sctp_high_prio_channel_port != forces_alternate_sctp_high_prio_channel_port))
880         dissector_delete_uint("sctp.port", alternate_sctp_high_prio_channel_port, forces_handle);
881     if ((forces_alternate_sctp_high_prio_channel_port != 0) &&
882         (alternate_sctp_high_prio_channel_port != forces_alternate_sctp_high_prio_channel_port))
883         dissector_add_uint("sctp.port", forces_alternate_sctp_high_prio_channel_port, forces_handle);
884     alternate_sctp_high_prio_channel_port = forces_alternate_sctp_high_prio_channel_port;
885
886     /* Register SCTP port for medium priority dissection */
887     if ((alternate_sctp_med_prio_channel_port != 0) &&
888         (alternate_sctp_med_prio_channel_port != forces_alternate_sctp_med_prio_channel_port))
889         dissector_delete_uint("udp.port", alternate_sctp_med_prio_channel_port, forces_handle);
890     if ((forces_alternate_sctp_med_prio_channel_port != 0) &&
891         (alternate_sctp_med_prio_channel_port != forces_alternate_sctp_med_prio_channel_port))
892         dissector_add_uint("udp.port", forces_alternate_sctp_med_prio_channel_port, forces_handle);
893     alternate_sctp_med_prio_channel_port = forces_alternate_sctp_med_prio_channel_port;
894
895     /* Register SCTP port for low priority dissection */
896     if ((alternate_sctp_low_prio_channel_port != 0) &&
897         (alternate_sctp_low_prio_channel_port != forces_alternate_sctp_low_prio_channel_port))
898         dissector_delete_uint("udp.port", alternate_sctp_low_prio_channel_port, forces_handle);
899     if ((forces_alternate_sctp_low_prio_channel_port != 0) &&
900         (alternate_sctp_low_prio_channel_port != forces_alternate_sctp_low_prio_channel_port))
901         dissector_add_uint("udp.port", forces_alternate_sctp_low_prio_channel_port, forces_handle);
902     alternate_sctp_low_prio_channel_port = forces_alternate_sctp_low_prio_channel_port;
903 }
904
905 /*
906 * Editor modelines - http://www.wireshark.org/tools/modelines.html
907 *
908 * Local variables:
909 * c-basic-offset: 4
910 * tab-width: 8
911 * indent-tabs-mode: nil
912 * End:
913 *
914 * vi: set shiftwidth=4 tabstop=8 expandtab:
915 * :indentSize=4:tabSize=8:noTabs=true:
916 */