/src/wireshark/epan/dissectors/packet-openflow.c
Line | Count | Source |
1 | | /* packet-openflow.c |
2 | | * Routines for OpenFlow dissection |
3 | | * Copyright 2013, Anders Broman <anders.broman@ericsson.com> |
4 | | * Copyright 2013, Zoltan Lajos Kis <zoltan.lajos.kis@ericsson.com> |
5 | | * |
6 | | * Wireshark - Network traffic analyzer |
7 | | * By Gerald Combs <gerald@wireshark.org> |
8 | | * Copyright 1998 Gerald Combs |
9 | | * |
10 | | * SPDX-License-Identifier: GPL-2.0-or-later |
11 | | * |
12 | | * Ref https://www.opennetworking.org/sdn-resources/onf-specifications/openflow |
13 | | */ |
14 | | |
15 | | #include "config.h" |
16 | | |
17 | | #include <epan/packet.h> |
18 | | #include <epan/expert.h> |
19 | | #include <epan/prefs.h> |
20 | | |
21 | | #include "packet-tcp.h" |
22 | | |
23 | | void proto_register_openflow(void); |
24 | | void proto_reg_handoff_openflow(void); |
25 | | |
26 | 2.80k | #define OFP_LEGACY_PORT 6633 |
27 | 2.80k | #define OFP_LEGACY2_PORT 6634 |
28 | 2.82k | #define OFP_IANA_PORT 6653 |
29 | | static range_t *g_openflow_ports; |
30 | | |
31 | | static dissector_handle_t openflow_handle; |
32 | | static dissector_handle_t openflow_v1_handle; |
33 | | static dissector_handle_t openflow_v4_handle; |
34 | | static dissector_handle_t openflow_v5_handle; |
35 | | static dissector_handle_t openflow_v6_handle; |
36 | | |
37 | | /* Initialize the protocol and registered fields */ |
38 | | static int proto_openflow; |
39 | | static int hf_openflow_version; |
40 | | |
41 | | static expert_field ei_openflow_version; |
42 | | |
43 | | static bool openflow_desegment = true; |
44 | | |
45 | 12 | #define OFP_VERSION_1_0 1 |
46 | | #define OFP_VERSION_1_1 2 |
47 | | #define OFP_VERSION_1_2 3 |
48 | 109 | #define OFP_VERSION_1_3 4 |
49 | 240 | #define OFP_VERSION_1_4 5 |
50 | 228 | #define OFP_VERSION_1_5 6 |
51 | | |
52 | | static const value_string openflow_version_values[] = { |
53 | | { OFP_VERSION_1_0, "1.0" }, |
54 | | { OFP_VERSION_1_1, "1.1" }, |
55 | | { OFP_VERSION_1_2, "1.2" }, |
56 | | { OFP_VERSION_1_3, "1.3" }, |
57 | | { OFP_VERSION_1_4, "1.4" }, |
58 | | { OFP_VERSION_1_5, "1.5" }, |
59 | | { 0, NULL } |
60 | | }; |
61 | | |
62 | | static unsigned |
63 | | get_openflow_pdu_length(packet_info *pinfo _U_, tvbuff_t *tvb, |
64 | | int offset, void *data _U_) |
65 | 611 | { |
66 | 611 | return tvb_get_ntohs(tvb, offset + 2); |
67 | 611 | } |
68 | | |
69 | | static int |
70 | | dissect_openflow_tcp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) |
71 | 610 | { |
72 | 610 | unsigned offset = 0; |
73 | 610 | uint8_t version; |
74 | 610 | proto_item* ti; |
75 | | |
76 | 610 | version = tvb_get_uint8(tvb, 0); |
77 | | /* Set the Protocol column to the constant string of openflow */ |
78 | 610 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "OpenFlow"); |
79 | 610 | col_clear(pinfo->cinfo,COL_INFO); |
80 | | |
81 | 610 | switch(version){ |
82 | 12 | case OFP_VERSION_1_0: |
83 | 12 | call_dissector(openflow_v1_handle, tvb, pinfo, tree); |
84 | 12 | break; |
85 | 109 | case OFP_VERSION_1_3: |
86 | 109 | call_dissector(openflow_v4_handle, tvb, pinfo, tree); |
87 | 109 | break; |
88 | 240 | case OFP_VERSION_1_4: |
89 | 240 | call_dissector(openflow_v5_handle, tvb, pinfo, tree); |
90 | 240 | break; |
91 | 228 | case OFP_VERSION_1_5: |
92 | 228 | call_dissector(openflow_v6_handle, tvb, pinfo, tree); |
93 | 228 | break; |
94 | 21 | default: |
95 | 21 | ti = proto_tree_add_item(tree, hf_openflow_version, tvb, offset, 1, ENC_BIG_ENDIAN); |
96 | 21 | expert_add_info(pinfo, ti, &ei_openflow_version); |
97 | 21 | break; |
98 | 610 | } |
99 | 62 | return tvb_reported_length(tvb); |
100 | 610 | } |
101 | | |
102 | 589 | #define OFP_HEADER_LEN 8 |
103 | | static int |
104 | | dissect_openflow(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) |
105 | 589 | { |
106 | 589 | tcp_dissect_pdus(tvb, pinfo, tree, openflow_desegment, OFP_HEADER_LEN, |
107 | 589 | get_openflow_pdu_length, dissect_openflow_tcp_pdu, data); |
108 | 589 | return tvb_captured_length(tvb); |
109 | 589 | } |
110 | | |
111 | | static bool |
112 | | dissect_openflow_heur(tvbuff_t *tvb, packet_info *pinfo, |
113 | | proto_tree *tree, void *data) |
114 | 2.80k | { |
115 | 2.80k | conversation_t *conversation = NULL; |
116 | | |
117 | 2.80k | if ((pinfo->destport != OFP_LEGACY_PORT) && |
118 | 2.80k | (pinfo->destport != OFP_LEGACY2_PORT) && |
119 | 2.80k | (pinfo->destport != OFP_IANA_PORT) && |
120 | 2.80k | (!value_is_in_range(g_openflow_ports, pinfo->destport))) { |
121 | 2.80k | return false; |
122 | 2.80k | } |
123 | | |
124 | 0 | conversation = find_or_create_conversation(pinfo); |
125 | 0 | conversation_set_dissector(conversation, openflow_handle); |
126 | |
|
127 | 0 | dissect_openflow(tvb, pinfo, tree, data); |
128 | 0 | return true; |
129 | 2.80k | } |
130 | | |
131 | | static void |
132 | | apply_openflow_prefs(void) |
133 | 15 | { |
134 | | /* Openflow uses the port preference for heuristics */ |
135 | 15 | g_openflow_ports = prefs_get_range_value("openflow", "tcp.port"); |
136 | 15 | } |
137 | | |
138 | | /* |
139 | | * Register the protocol with Wireshark. |
140 | | */ |
141 | | void |
142 | | proto_register_openflow(void) |
143 | 15 | { |
144 | 15 | static hf_register_info hf[] = { |
145 | 15 | { &hf_openflow_version, |
146 | 15 | { "Version", "openflow.version", |
147 | 15 | FT_UINT8, BASE_HEX, VALS(openflow_version_values), 0x7f, |
148 | 15 | NULL, HFILL } |
149 | 15 | } |
150 | 15 | }; |
151 | | |
152 | 15 | static ei_register_info ei[] = { |
153 | 15 | { &ei_openflow_version, { "openflow.version.unknown", PI_UNDECODED, PI_WARN, "Unsupported version not dissected", EXPFILL }}, |
154 | 15 | }; |
155 | | |
156 | 15 | module_t *openflow_module; |
157 | 15 | expert_module_t* expert_openflow; |
158 | | |
159 | | /* Register the protocol name and description */ |
160 | 15 | proto_openflow = proto_register_protocol("OpenFlow", "OpenFlow", "openflow"); |
161 | | |
162 | 15 | openflow_handle = register_dissector("openflow", dissect_openflow, proto_openflow); |
163 | | |
164 | | /* Required function calls to register the header fields and subtrees */ |
165 | 15 | proto_register_field_array(proto_openflow, hf, array_length(hf)); |
166 | 15 | expert_openflow = expert_register_protocol(proto_openflow); |
167 | 15 | expert_register_field_array(expert_openflow, ei, array_length(ei)); |
168 | | |
169 | 15 | openflow_module = prefs_register_protocol(proto_openflow, apply_openflow_prefs); |
170 | | |
171 | | /* Register heuristic preference */ |
172 | 15 | prefs_register_obsolete_preference(openflow_module, "heuristic"); |
173 | | |
174 | | /* Register desegment preference */ |
175 | 15 | prefs_register_bool_preference(openflow_module, "desegment", |
176 | 15 | "Reassemble OpenFlow messages spanning multiple TCP segments", |
177 | 15 | "Whether the OpenFlow dissector should reassemble messages spanning multiple TCP segments." |
178 | 15 | " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.", |
179 | 15 | &openflow_desegment); |
180 | 15 | } |
181 | | |
182 | | void |
183 | | proto_reg_handoff_openflow(void) |
184 | 15 | { |
185 | 15 | heur_dissector_add("tcp", dissect_openflow_heur, "OpenFlow over TCP", "openflow_tcp", proto_openflow, HEURISTIC_ENABLE); |
186 | | |
187 | 15 | dissector_add_uint_with_preference("tcp.port", OFP_IANA_PORT, openflow_handle); |
188 | | |
189 | 15 | openflow_v1_handle = find_dissector_add_dependency("openflow_v1", proto_openflow); |
190 | 15 | openflow_v4_handle = find_dissector_add_dependency("openflow_v4", proto_openflow); |
191 | 15 | openflow_v5_handle = find_dissector_add_dependency("openflow_v5", proto_openflow); |
192 | 15 | openflow_v6_handle = find_dissector_add_dependency("openflow_v6", proto_openflow); |
193 | 15 | apply_openflow_prefs(); |
194 | 15 | } |
195 | | |
196 | | /* |
197 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
198 | | * |
199 | | * Local variables: |
200 | | * c-basic-offset: 4 |
201 | | * tab-width: 8 |
202 | | * indent-tabs-mode: nil |
203 | | * End: |
204 | | * |
205 | | * vi: set shiftwidth=4 tabstop=8 expandtab: |
206 | | * :indentSize=4:tabSize=8:noTabs=true: |
207 | | */ |