2 * Routines for CPFI Cross Point Frame Injector dissection
3 * CPFI - Cross Point Frame Injector is a CNT proprietary
4 * protocol used to carry Fibre Channel data over UDP
6 * Copyright 2003, Dave Sclarsky <dave_sclarsky[AT]cnt.com>
10 * Wireshark - Network traffic analyzer
11 * By Gerald Combs <gerald@wireshark.org>
12 * Copyright 1998 Gerald Combs
14 * Copied from packet-m2tp.c
15 * Thanks to Heinz Prantner for his motivation and assistance
17 * This program is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU General Public License
19 * as published by the Free Software Foundation; either version 2
20 * of the License, or (at your option) any later version.
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
36 #include <epan/packet.h>
37 #include <epan/prefs.h>
39 void proto_register_cpfi(void);
40 void proto_reg_handoff_cpfi(void);
42 #define CPFI_DEFAULT_UDP_PORT 5000
43 #define CPFI_DEFAULT_TTOT_UDP_PORT 5001
45 #define FIRST_TIO_CARD_ADDRESS 0x380
49 #define CPFI_FRAME_TYPE_MASK 0xF0000000
50 #define CPFI_FRAME_TYPE_SHIFT 28
51 #define CPFI_SOURCE_MASK 0x0FFC0000
52 #define CPFI_SOURCE_SHIFT 18
53 #define CPFI_DEST_MASK 0x0003FF00
54 #define CPFI_DEST_SHIFT 8
55 #define CPFI_SOF_TYPE_MASK 0x000000F0
56 #define CPFI_SPEED_MASK 0x0000000C
57 #define CPFI_OPM_ERROR_MASK 0x00000002
58 #define CPFI_FROM_LCM_MASK 0x00000001
61 #define CPFI_EOF_TYPE_MASK 0x78000000
62 #define CPFI_EOF_ERROR_MASK 0x7FE00000
64 /* configurable parameters */
65 static guint gbl_cpfi_udp_port
= CPFI_DEFAULT_UDP_PORT
;
66 static guint gbl_cpfi_ttot_udp_port
= CPFI_DEFAULT_TTOT_UDP_PORT
;
67 static gboolean cpfi_arrow_moves
= TRUE
;
69 /* Initialize the protocol and registered fields */
70 static int proto_cpfi
= -1;
71 static int hf_cpfi_word_one
= -1;
72 static int hf_cpfi_word_two
= -1;
74 static int hf_cpfi_frame_type
= -1;
75 static int hf_cpfi_source
= -1;
76 static int hf_cpfi_dest
= -1;
77 static int hf_cpfi_SOF_type
= -1;
78 static int hf_cpfi_speed
= -1;
79 static int hf_cpfi_OPM_error
= -1;
80 static int hf_cpfi_from_LCM
= -1;
82 static int hf_cpfi_CRC_32
= -1;
83 static int hf_cpfi_EOF_type
= -1;
85 static int hf_cpfi_t_instance
= -1;
86 static int hf_cpfi_t_src_instance
= -1;
87 static int hf_cpfi_t_dst_instance
= -1;
88 static int hf_cpfi_t_board
= -1;
89 static int hf_cpfi_t_src_board
= -1;
90 static int hf_cpfi_t_dst_board
= -1;
91 static int hf_cpfi_t_port
= -1;
92 static int hf_cpfi_t_src_port
= -1;
93 static int hf_cpfi_t_dst_port
= -1;
97 static guint8 frame_type
;
98 static char src_str
[20];
99 static char dst_str
[20];
100 static char l_to_r_arrow
[] = "-->";
101 static char r_to_l_arrow
[] = "<--";
102 static const char *left
= src_str
;
103 static const char *right
= dst_str
;
104 static const char *arrow
= l_to_r_arrow
;
105 static const char direction_and_port_string
[] = "[%s %s %s] ";
108 /* Initialize the subtree pointers */
109 static gint ett_cpfi
= -1;
110 static gint ett_cpfi_header
= -1;
111 static gint ett_cpfi_footer
= -1;
113 static dissector_handle_t fc_handle
;
116 static const value_string sof_type_vals
[] = {
131 static const value_string speed_vals
[] = {
139 static const value_string eof_type_vals
[] = {
153 dissect_cpfi_header(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
157 guint8 src_instance
= 0;
158 guint8 src_board
= 0;
161 guint8 dst_instance
= 0;
162 guint8 dst_board
= 0;
164 proto_item
*extra_item
= NULL
;
165 proto_tree
*extra_tree
= NULL
;
166 proto_item
*hidden_item
;
168 /* add a tree for the header */
171 extra_item
= proto_tree_add_protocol_format(tree
, proto_cpfi
, tvb
, 0, -1, "Header");
172 extra_tree
= proto_item_add_subtree(extra_item
, ett_cpfi_header
);
175 /* Extract the common header, and get the bits we need */
176 word1
= tvb_get_ntohl (tvb
, 0);
177 word2
= tvb_get_ntohl (tvb
, sizeof(word1
));
179 /* Figure out where the frame came from. dstTDA is source of frame! */
180 tda
= (word1
& CPFI_DEST_MASK
) >> CPFI_DEST_SHIFT
;
181 if ( tda
>= FIRST_TIO_CARD_ADDRESS
)
183 g_strlcpy(src_str
, " CPFI", sizeof(src_str
));
184 src
= 0; /* Make it smallest */
188 const guint8
*srcmac
;
190 /* Make sure this is an Ethernet address. */
191 DISSECTOR_ASSERT(pinfo
->src
.type
== AT_ETHER
);
192 srcmac
= (const guint8
*)pinfo
->src
.data
;
194 src_instance
= srcmac
[2]-1;
195 src_board
= tda
>> 4;
196 src_port
= tda
& 0x0f;
197 src
= (1 << 24) + (src_instance
<< 16) + (src_board
<< 8) + src_port
;
198 g_snprintf(src_str
, sizeof(src_str
), "%u.%u.%u", src_instance
, src_board
, src_port
);
201 /* Figure out where the frame is going. srcTDA is destination of frame! */
202 tda
= (word1
& CPFI_SOURCE_MASK
) >> CPFI_SOURCE_SHIFT
;
203 if ( tda
>= FIRST_TIO_CARD_ADDRESS
)
205 g_strlcpy(dst_str
, " CPFI", sizeof(dst_str
));
206 dst
= 0; /* Make it smallest */
210 const guint8
*dstmac
;
212 /* Make sure this is an Ethernet address. */
213 DISSECTOR_ASSERT(pinfo
->dst
.type
== AT_ETHER
);
214 dstmac
= (const guint8
*)pinfo
->dst
.data
;
216 dst_instance
= dstmac
[2]-1;
217 dst_board
= tda
>> 4;
218 dst_port
= tda
& 0x0f;
219 dst
= (1 << 24) + (dst_instance
<< 16) + (dst_board
<< 8) + dst_port
;
220 g_snprintf(dst_str
, sizeof(dst_str
), "%u.%u.%u", dst_instance
, dst_board
, dst_port
);
223 /* Set up the source and destination and arrow per user configuration. */
224 if ( cpfi_arrow_moves
&& (dst
< src
) )
227 arrow
= r_to_l_arrow
;
233 arrow
= l_to_r_arrow
;
238 /* For "real" TDAs (i.e. not for microTDAs), add hidden addresses to allow filtering */
241 hidden_item
= proto_tree_add_bytes(extra_tree
, hf_cpfi_t_instance
, tvb
, 0, 1, &src_instance
);
242 PROTO_ITEM_SET_HIDDEN(hidden_item
);
243 hidden_item
= proto_tree_add_bytes(extra_tree
, hf_cpfi_t_src_instance
, tvb
, 0, 1, &src_instance
);
244 PROTO_ITEM_SET_HIDDEN(hidden_item
);
245 hidden_item
= proto_tree_add_bytes(extra_tree
, hf_cpfi_t_board
, tvb
, 0, 1, &src_board
);
246 PROTO_ITEM_SET_HIDDEN(hidden_item
);
247 hidden_item
= proto_tree_add_bytes(extra_tree
, hf_cpfi_t_src_board
, tvb
, 0, 1, &src_board
);
248 PROTO_ITEM_SET_HIDDEN(hidden_item
);
249 hidden_item
= proto_tree_add_bytes(extra_tree
, hf_cpfi_t_port
, tvb
, 0, 1, &src_port
);
250 PROTO_ITEM_SET_HIDDEN(hidden_item
);
251 hidden_item
= proto_tree_add_bytes(extra_tree
, hf_cpfi_t_src_port
, tvb
, 0, 1, &src_port
);
252 PROTO_ITEM_SET_HIDDEN(hidden_item
);
256 hidden_item
= proto_tree_add_bytes(extra_tree
, hf_cpfi_t_instance
, tvb
, 0, 1, &dst_instance
);
257 PROTO_ITEM_SET_HIDDEN(hidden_item
);
258 hidden_item
= proto_tree_add_bytes(extra_tree
, hf_cpfi_t_dst_instance
, tvb
, 0, 1, &dst_instance
);
259 PROTO_ITEM_SET_HIDDEN(hidden_item
);
260 hidden_item
= proto_tree_add_bytes(extra_tree
, hf_cpfi_t_board
, tvb
, 0, 1, &dst_board
);
261 PROTO_ITEM_SET_HIDDEN(hidden_item
);
262 hidden_item
= proto_tree_add_bytes(extra_tree
, hf_cpfi_t_dst_board
, tvb
, 0, 1, &dst_board
);
263 PROTO_ITEM_SET_HIDDEN(hidden_item
);
264 hidden_item
= proto_tree_add_bytes(extra_tree
, hf_cpfi_t_port
, tvb
, 0, 1, &dst_port
);
265 PROTO_ITEM_SET_HIDDEN(hidden_item
);
266 hidden_item
= proto_tree_add_bytes(extra_tree
, hf_cpfi_t_dst_port
, tvb
, 0, 1, &dst_port
);
267 PROTO_ITEM_SET_HIDDEN(hidden_item
);
270 /* add word 1 components to the protocol tree */
271 proto_tree_add_item(extra_tree
, hf_cpfi_word_one
, tvb
, 0, 4, ENC_BIG_ENDIAN
);
273 proto_tree_add_item(extra_tree
, hf_cpfi_frame_type
, tvb
, 0, 4, ENC_BIG_ENDIAN
);
274 proto_tree_add_item(extra_tree
, hf_cpfi_source
, tvb
, 0, 4, ENC_BIG_ENDIAN
);
275 proto_tree_add_item(extra_tree
, hf_cpfi_dest
, tvb
, 0, 4, ENC_BIG_ENDIAN
);
276 proto_tree_add_item(extra_tree
, hf_cpfi_SOF_type
, tvb
, 0, 4, ENC_BIG_ENDIAN
);
277 proto_tree_add_item(extra_tree
, hf_cpfi_speed
, tvb
, 0, 4, ENC_BIG_ENDIAN
);
278 proto_tree_add_item(extra_tree
, hf_cpfi_OPM_error
, tvb
, 0, 4, ENC_BIG_ENDIAN
);
279 proto_tree_add_item(extra_tree
, hf_cpfi_from_LCM
, tvb
, 0, 4, ENC_BIG_ENDIAN
);
281 /* add word 2 components to the protocol tree */
282 proto_tree_add_item(extra_tree
, hf_cpfi_word_two
, tvb
, 4, 4, ENC_BIG_ENDIAN
);
288 dissect_cpfi_footer(tvbuff_t
*tvb
, proto_tree
*tree
)
290 proto_item
*extra_item
= NULL
;
291 proto_tree
*extra_tree
= NULL
;
293 /* add a tree for the footer */
296 extra_item
= proto_tree_add_protocol_format(tree
, proto_cpfi
, tvb
, 0, -1, "Footer");
297 extra_tree
= proto_item_add_subtree(extra_item
, ett_cpfi_footer
);
301 proto_tree_add_item(extra_tree
, hf_cpfi_CRC_32
, tvb
, 0, 4, ENC_BIG_ENDIAN
);
302 proto_tree_add_item(extra_tree
, hf_cpfi_EOF_type
, tvb
, 4, 4, ENC_BIG_ENDIAN
);
308 dissect_cpfi(tvbuff_t
*message_tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
310 tvbuff_t
*header_tvb
, *body_tvb
, *footer_tvb
;
311 proto_item
*cpfi_item
= NULL
;
312 proto_tree
*cpfi_tree
= NULL
;
313 gint length
, reported_length
, body_length
, reported_body_length
;
315 frame_type
= (tvb_get_ntohl (message_tvb
, 0) & CPFI_FRAME_TYPE_MASK
) >> CPFI_FRAME_TYPE_SHIFT
;
317 /* If this is not a CPFI frame, return 0 to let another dissector try to
320 if ( !((frame_type
== 9) && fc_handle
) )
323 /* If we don't have Ethernet addresses, can't do further dissection... */
324 if (pinfo
->dst
.type
!= AT_ETHER
|| pinfo
->src
.type
!= AT_ETHER
)
327 length
= tvb_length_remaining(message_tvb
, 8);
328 reported_length
= tvb_reported_length_remaining(message_tvb
, 8);
329 if (reported_length
< 8)
331 /* We don't even have enough for the footer. */
335 /* Length of packet, minus the footer. */
336 reported_body_length
= reported_length
- 8;
337 /* How much of that do we have in the tvbuff? */
338 body_length
= length
;
339 if (body_length
> reported_body_length
)
340 body_length
= reported_body_length
;
342 length
= tvb_length_remaining(message_tvb
, 8+body_length
);
345 /* The footer wasn't captured at all.
346 XXX - we'd like to throw a BoundsError if that's the case. */
350 /* In the interest of speed, if "tree" is NULL, don't do any work not
351 necessary to generate protocol tree items. */
353 /* create the protocol tree */
354 cpfi_item
= proto_tree_add_item(tree
, proto_cpfi
, message_tvb
, 0, -1, ENC_NA
);
355 cpfi_tree
= proto_item_add_subtree(cpfi_item
, ett_cpfi
);
358 /* Set up the frame controls - can we do better than this? */
360 pinfo
->sof_eof
= PINFO_SOF_FIRST_FRAME
;
361 pinfo
->sof_eof
|= PINFO_EOF_LAST_FRAME
;
362 pinfo
->sof_eof
|= PINFO_EOF_INVALID
;
364 /* dissect the message */
366 /* extract and process the header */
367 header_tvb
= tvb_new_subset(message_tvb
, 0, 8, 8);
368 dissect_cpfi_header(header_tvb
, pinfo
, cpfi_tree
);
370 body_tvb
= tvb_new_subset(message_tvb
, 8, body_length
, reported_body_length
);
371 call_dissector(fc_handle
, body_tvb
, pinfo
, tree
);
373 /* add more info, now that FC added its */
374 proto_item_append_text(cpfi_item
, direction_and_port_string
, left
, arrow
, right
);
375 col_prepend_fstr(pinfo
->cinfo
, COL_INFO
, direction_and_port_string
, left
, arrow
, right
);
378 footer_tvb
= tvb_new_subset(message_tvb
, 8+body_length
, length
, 8);
379 dissect_cpfi_footer(footer_tvb
, cpfi_tree
);
381 return(tvb_length(message_tvb
));
385 /* Register the protocol with Wireshark */
387 proto_register_cpfi(void)
389 module_t
*cpfi_module
;
391 /* Setup list of header fields */
392 static hf_register_info hf
[] = {
395 { "Word one", "cpfi.word_one",
396 FT_UINT32
, BASE_HEX
, NULL
, 0x0,
399 { "Word two", "cpfi.word_two",
400 FT_UINT32
, BASE_HEX
, NULL
, 0x0,
403 { &hf_cpfi_frame_type
,
404 { "FrmType", "cpfi.frmtype",
405 FT_UINT32
, BASE_HEX
, NULL
, CPFI_FRAME_TYPE_MASK
,
406 "Frame Type", HFILL
}},
408 { "srcTDA", "cpfi.srcTDA",
409 FT_UINT32
, BASE_HEX
, NULL
, CPFI_SOURCE_MASK
,
410 "Source TDA (10 bits)", HFILL
}},
412 { "dstTDA", "cpfi.dstTDA",
413 FT_UINT32
, BASE_HEX
, NULL
, CPFI_DEST_MASK
,
414 "Source TDA (10 bits)", HFILL
}},
416 { "SOFtype", "cpfi.SOFtype",
417 FT_UINT32
, BASE_HEX
, VALS(sof_type_vals
), CPFI_SOF_TYPE_MASK
,
420 { "speed", "cpfi.speed",
421 FT_UINT32
, BASE_HEX
, VALS(speed_vals
), CPFI_SPEED_MASK
,
423 { &hf_cpfi_OPM_error
,
424 { "OPMerror", "cpfi.OPMerror",
425 FT_BOOLEAN
, 32, NULL
, CPFI_OPM_ERROR_MASK
,
426 "OPM Error?", HFILL
}},
428 { "fromLCM", "cpfi.fromLCM",
429 FT_BOOLEAN
, 32, NULL
, CPFI_FROM_LCM_MASK
,
430 "from LCM?", HFILL
}},
433 { "CRC-32", "cpfi.crc-32",
434 FT_UINT32
, BASE_HEX
, NULL
, 0x0,
438 { "EOFtype", "cpfi.EOFtype",
439 FT_UINT32
, BASE_HEX
, VALS(eof_type_vals
), CPFI_EOF_TYPE_MASK
,
442 { &hf_cpfi_t_instance
,
443 { "Instance", "cpfi.instance",
445 NULL
, 0x0, NULL
, HFILL
}},
447 { &hf_cpfi_t_src_instance
,
448 { "Source Instance", "cpfi.src_instance",
450 NULL
, 0x0, NULL
, HFILL
}},
452 { &hf_cpfi_t_dst_instance
,
453 { "Destination Instance", "cpfi.dst_instance",
455 NULL
, 0x0, NULL
, HFILL
}},
458 { "Board", "cpfi.board",
460 NULL
, 0x0, NULL
, HFILL
}},
462 { &hf_cpfi_t_src_board
,
463 { "Source Board", "cpfi.src_board",
465 NULL
, 0x0, NULL
, HFILL
}},
467 { &hf_cpfi_t_dst_board
,
468 { "Destination Board", "cpfi.dst_board",
470 NULL
, 0x0, NULL
, HFILL
}},
473 { "Port", "cpfi.port",
475 NULL
, 0x0, NULL
, HFILL
}},
477 { &hf_cpfi_t_src_port
,
478 { "Source Port", "cpfi.src_port",
480 NULL
, 0x0, NULL
, HFILL
}},
482 { &hf_cpfi_t_dst_port
,
483 { "Destination Port", "cpfi.dst_port",
485 NULL
, 0x0, NULL
, HFILL
}},
489 /* Setup protocol subtree array */
490 static gint
*ett
[] = {
497 /* Register the protocol name and description */
498 proto_cpfi
= proto_register_protocol("Cross Point Frame Injector", "CPFI", "cpfi");
500 /* Required function calls to register the header fields and subtrees used */
501 proto_register_field_array(proto_cpfi
, hf
, array_length(hf
));
502 proto_register_subtree_array(ett
, array_length(ett
));
504 /* Register our configuration options for CPFI */
505 cpfi_module
= prefs_register_protocol(proto_cpfi
, proto_reg_handoff_cpfi
);
506 prefs_register_uint_preference(cpfi_module
, "udp.port", "CPFI UDP Port",
507 "Set the port for CPFI messages (if other"
508 " than the default of 5000)",
509 10, &gbl_cpfi_udp_port
);
510 prefs_register_uint_preference(cpfi_module
, "udp.port2", "InstanceToInstance UDP Port",
511 "Set the port for InstanceToInstance messages (if other"
512 " than the default of 5001)",
513 10, &gbl_cpfi_ttot_udp_port
);
514 prefs_register_bool_preference(cpfi_module
, "arrow_ctl",
515 "Enable Active Arrow Control",
516 "Control the way the '-->' is displayed."
517 " When enabled, keeps the 'lowest valued' endpoint of the src-dest pair"
518 " on the left, and the arrow moves to distinguish source from dest."
519 " When disabled, keeps the arrow pointing right so the source of the frame"
520 " is always on the left.",
526 proto_reg_handoff_cpfi(void)
528 static gboolean cpfi_init_complete
= FALSE
;
529 static dissector_handle_t cpfi_handle
;
530 static dissector_handle_t ttot_handle
;
531 static guint cpfi_udp_port
;
532 static guint cpfi_ttot_udp_port
;
534 if ( !cpfi_init_complete
)
536 fc_handle
= find_dissector("fc");
537 cpfi_handle
= new_create_dissector_handle(dissect_cpfi
, proto_cpfi
);
538 ttot_handle
= new_create_dissector_handle(dissect_cpfi
, proto_cpfi
);
539 cpfi_init_complete
= TRUE
;
543 dissector_delete_uint("udp.port", cpfi_udp_port
, cpfi_handle
);
544 dissector_delete_uint("udp.port", cpfi_ttot_udp_port
, ttot_handle
);
547 cpfi_udp_port
= gbl_cpfi_udp_port
;
548 cpfi_ttot_udp_port
= gbl_cpfi_ttot_udp_port
;
550 dissector_add_uint("udp.port", cpfi_udp_port
, cpfi_handle
);
551 dissector_add_uint("udp.port", cpfi_ttot_udp_port
, ttot_handle
);