### Bug Summary

File: | builds/wireshark/wireshark/epan/conversation.c
Warning: | line 3321, column 5 Null returned from a function that is expected to return a non-null value

### Annotated Source Code

Press '?' to see keyboard shortcuts

Show analyzer invocation
clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name conversation.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -fno-delete-null-pointer-checks -mframe-pointer=all -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -ffloat16-excess-precision=fast -fbfloat16-excess-precision=fast -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/builds/wireshark/wireshark/build -fcoverage-compilation-dir=/builds/wireshark/wireshark/build -resource-dir /usr/lib/llvm-22/lib/clang/22 -isystem /usr/include/glib-2.0 -isystem /usr/lib/x86_64-linux-gnu/glib-2.0/include -isystem /builds/wireshark/wireshark/epan -isystem /builds/wireshark/wireshark/build/epan -isystem /usr/include/mit-krb5 -isystem /usr/include/lua5.5 -isystem /usr/include/libxml2 -D CARES_NO_DEPRECATED -D G_DISABLE_DEPRECATED -D G_DISABLE_SINGLE_INCLUDES -D REX_API=extern -D WS_BUILD_DLL -D WS_DEBUG -D WS_DEBUG_UTF_8 -D epan_EXPORTS -I /builds/wireshark/wireshark/build -I /builds/wireshark/wireshark -I /builds/wireshark/wireshark/include -I /builds/wireshark/wireshark/wiretap -D _GLIBCXX_ASSERTIONS -internal-isystem /usr/lib/llvm-22/lib/clang/22/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/builds/wireshark/wireshark/= -fmacro-prefix-map=/builds/wireshark/wireshark/build/= -fmacro-prefix-map=../= -Wno-format-nonliteral -std=gnu17 -ferror-limit 19 -fvisibility=hidden -fwrapv -fwrapv-pointer -fstrict-flex-arrays=3 -stack-protector 2 -fstack-clash-protection -fcf-protection=full -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fexceptions -fcolor-diagnostics -analyzer-output=html -faddrsig -fdwarf2-cfi-asm -o /builds/wireshark/wireshark/sbout/2026-08-26-100403-3659-1 -x c /builds/wireshark/wireshark/epan/conversation.c

Keyboard shortcuts:

- Use 'j/k' keys for keyboard navigation
- Use 'Shift+S' to show/hide relevant lines
- Use '?' to toggle this window

Close
Show only relevant lines Show control flow arrows

1 | /* conversation.c
2 | * Routines for building lists of packets that are part of a "conversation"
3 | *
4 | * Wireshark - Network traffic analyzer
5 | * By Gerald Combs <gerald@wireshark.org>
6 | * Copyright 1998 Gerald Combs
7 | *
8 | * SPDX-License-Identifier: GPL-2.0-or-later
9 | */
10 |
11 | #include "config.h"
12 |
13 | #include <string.h>
14 |
15 | #include <glib.h>
16 |
17 | #include <wiretap/wtap.h>
18 | #include <wsutil/array.h>
19 |
20 | #include <epan/packet.h>
21 | #include "to_str.h"
22 | #include "conversation.h"
23 |
24 | // The conversation database is a map of maps that contain conversation_t's.
25 | // Top-level map keys are strings that describe each conversation type.
26 | // Second-level map keys are conversation_element_t arrays.
27 | // {
28 | // "uint,endpoint": {
29 | // [ { type: CE_ADDR, addr_val: 10.20.30.40}, { type: CE_PORT, uint_val: 80 } ... ]: <conversation_t>
30 | // [ { type: CE_ADDR, addr_val: 1.1.1.1}, { type: CE_PORT, uint_val: 53 } ... ]: <conversation_t>
31 | // }
32 | // }
33 | // Instead of using strings as keys we could bit-shift conversation endpoint types
34 | // into a uint64_t, e.g. 0x0000000102010200 for CE_ADDRESS,CE_PORT,CE_ADDRESS,CE_PORT,CE_CONVERSATION_TYPE.
35 | // We could also use this to prepend a type+length indicator for element arrays.
36 |
37 | /* define DEBUG_CONVERSATION for pretty debug printing */
38 | /* #define DEBUG_CONVERSATION */
39 | #include "conversation_debug.h"
40 |
41 | #ifdef DEBUG_CONVERSATION
42 | int _debug_conversation_indent;
43 | #endif
44 |
45 | /*
46 | * We could use an element list here, but this is effectively a parameter list
47 | * for find_conversation and is more compact.
48 | */
49 | struct conversation_addr_port_endpoints {
50 | address addr1;
51 | address addr2;
52 | uint32_t port1;
53 | uint32_t port2;
54 | conversation_type ctype;
55 | };
56 |
57 | /* Element offsets for address+port conversations */
58 | enum {
59 | ADDR1_IDX,
60 | PORT1_IDX,
61 | ADDR2_IDX,
62 | PORT2_IDX,
63 | ENDP_EXACT_IDX,
64 | EXACT_IDX_COUNT,
65 | ADDRS_IDX_COUNT = PORT2_IDX,
66 | PORT2_NO_ADDR2_IDX = ADDR2_IDX,
67 | ENDP_NO_ADDR2_IDX = PORT2_IDX,
68 | ENDP_NO_PORT2_IDX = PORT2_IDX,
69 | ENDP_NO_ADDR2_PORT2_IDX = ADDR2_IDX,
70 | NO_ADDR2_IDX_COUNT = ENDP_EXACT_IDX,
71 | NO_PORT2_IDX_COUNT = ENDP_EXACT_IDX,
72 | NO_ADDR2_PORT2_IDX_COUNT = PORT2_IDX,
73 | ENDP_NO_PORTS_IDX = ADDR2_IDX,
74 | ERR_PKTS_COUNT = PORT2_IDX
75 | };
76 |
77 | /* Element offsets for the deinterlacer conversations */
78 | enum {
79 | DEINTR_ADDR1_IDX,
80 | DEINTR_ADDR2_IDX,
81 | DEINTR_KEY1_IDX,
82 | DEINTR_KEY2_IDX,
83 | DEINTR_KEY3_IDX,
84 | DEINTR_ENDP_IDX
85 | };
86 |
87 | /* Element offsets for the deinterlaced conversations */
88 | enum {
89 | DEINTD_ADDR1_IDX,
90 | DEINTD_ADDR2_IDX,
91 | DEINTD_PORT1_IDX,
92 | DEINTD_PORT2_IDX,
93 | DEINTD_ENDP_EXACT_IDX,
94 | DEINTD_EXACT_IDX_COUNT,
95 | DEINTD_ADDRS_IDX_COUNT = DEINTD_PORT2_IDX,
96 | DEINTD_ENDP_NO_PORTS_IDX = DEINTD_PORT1_IDX,
97 | DEINTD_NO_ADDR2_IDX_COUNT = DEINTD_EXACT_IDX_COUNT,
98 | DEINTD_NO_PORT2_IDX_COUNT = DEINTD_EXACT_IDX_COUNT,
99 | DEINTD_NO_ADDR2_PORT2_IDX_COUNT = DEINTD_ENDP_EXACT_IDX
100 | };
101 |
102 | /* Names for conversation_element_type values. */
103 | static const char * const type_names[] = {
104 | "endpoint",
105 | "address",
106 | "port",
107 | "string",
108 | "uint",
109 | "uint64",
110 | "int",
111 | "int64",
112 | "blob",
113 | };
114 |
115 | /*
116 | * Getters to for struct conversation_addr_port_endpoints.
117 | * packet_info.h:{PINFO_{SRC,DST,...} macros for the reason.
118 | */
119 | address *conversation_addr_port_endpoints_addr1(struct conversation_addr_port_endpoints *endpoints) {
120 | return &endpoints->addr1;
121 | }
122 | address *conversation_addr_port_endpoints_addr2(struct conversation_addr_port_endpoints *endpoints) {
123 | return &endpoints->addr2;
124 | }
125 | uint32_t conversation_addr_port_endpoints_port1(struct conversation_addr_port_endpoints *endpoints) {
126 | return endpoints->port1;
127 | }
128 | uint32_t conversation_addr_port_endpoints_port2(struct conversation_addr_port_endpoints *endpoints) {
129 | return endpoints->port2;
130 | }
131 |
132 | /*
133 | * Hash table of hash tables for conversations identified by element lists.
134 | */
135 | static wmem_map_t *conversation_hashtable_element_list;
136 |
137 | /*
138 | * Hash table for conversations based on addresses only
139 | */
140 | static wmem_map_t *conversation_hashtable_exact_addr;
141 |
142 | /*
143 | * Hash table for conversations with no wildcards.
144 | */
145 | static wmem_map_t *conversation_hashtable_exact_addr_port;
146 |
147 | /*
148 | * Hash table for conversations with one wildcard address.
149 | */
150 | static wmem_map_t *conversation_hashtable_no_addr2;
151 |
152 | /*
153 | * Hash table for conversations with one wildcard port.
154 | */
155 | static wmem_map_t *conversation_hashtable_no_port2;
156 |
157 | /*
158 | * Hash table for conversations with one wildcard address and port.
159 | */
160 | static wmem_map_t *conversation_hashtable_no_addr2_or_port2;
161 |
162 | /*
163 | * Hash table for conversations with a single unsigned ID number.
164 | */
165 | static wmem_map_t *conversation_hashtable_id;
166 |
167 | /*
168 | * Hash table for conversations with no wildcards, and an anchor
169 | */
170 | static wmem_map_t *conversation_hashtable_exact_addr_port_anc = NULL((void*)0);
171 |
172 | /*
173 | * Hash table for conversations based on addresses only, and an anchor
174 | */
175 | static wmem_map_t *conversation_hashtable_exact_addr_anc = NULL((void*)0);
176 |
177 | /*
178 | * Hash table for conversations with one wildcard address, and an anchor
179 | */
180 | static wmem_map_t *conversation_hashtable_no_addr2_anc = NULL((void*)0);
181 |
182 | /*
183 | * Hash table for conversations with one wildcard port, and an anchor
184 | */
185 | static wmem_map_t *conversation_hashtable_no_port2_anc = NULL((void*)0);
186 |
187 | /*
188 | * Hash table for conversations with one wildcard address and port, and an anchor.
189 | */
190 | static wmem_map_t *conversation_hashtable_no_addr2_or_port2_anc;
191 |
192 | /*
193 | * Hash table for deinterlacing conversations (typically L1 or L2)
194 | */
195 | static wmem_map_t *conversation_hashtable_deinterlacer = NULL((void*)0);
196 |
197 | /*
198 | * Hash table for tracking conversations involved in error packets.
199 | * Conversations stored here don't have an autonomous existence,
200 | * strictly speaking, but are a reference to other ones stored in
201 | * other tables (such as conversation_hashtable_exact_addr_port).
202 | * This table should be understood as an outgrowth of other tables.
203 | * Note on this table keys: they are composed of 3 elements:
204 | * id : the conv_index for this conversation in this table
205 | * rid : reference conv_index for the transport conversation
206 | * stored in table conversation_hashtable_exact_addr_port
207 | * ctype: conversation type of the transport conversation
208 | */
209 | static wmem_map_t *conversation_hashtable_err_pkts = NULL((void*)0);
210 |
211 | static uint32_t new_index;
212 |
213 | /*
214 | * Placeholder for address-less conversations.
215 | */
216 | static address null_address_ = ADDRESS_INIT_NONE{AT_NONE, 0, ((void*)0), ((void*)0)};
217 |
218 |
219 | /* Element count including the terminating CE_CONVERSATION_TYPE */
220 | #define MAX_CONVERSATION_ELEMENTS8 8 // Arbitrary.
221 | static size_t
222 | conversation_element_count(conversation_element_t *elements)
223 | {
224 | size_t count = 0;
225 | while (elements[count].type != CE_CONVERSATION_TYPE) {
226 | count++;
227 | DISSECTOR_ASSERT(count < MAX_CONVERSATION_ELEMENTS)((void) ((count < 8) ? (void)0 : (proto_report_dissector_bug ("%s:%u: failed assertion \"%s\"", "epan/conversation.c", 227 , "count < 8"))));
228 | }
229 | count++;
230 | // Keying on the endpoint type alone isn't very useful.
231 | DISSECTOR_ASSERT(count > 1)((void) ((count > 1) ? (void)0 : (proto_report_dissector_bug ("%s:%u: failed assertion \"%s\"", "epan/conversation.c", 231 , "count > 1"))));
232 | return count;
233 | }
234 |
235 | static conversation_type
236 | conversation_get_key_type(conversation_element_t *elements)
237 | {
238 | size_t count = 0;
239 | while (elements[count].type != CE_CONVERSATION_TYPE) {
240 | count++;
241 | DISSECTOR_ASSERT(count < MAX_CONVERSATION_ELEMENTS)((void) ((count < 8) ? (void)0 : (proto_report_dissector_bug ("%s:%u: failed assertion \"%s\"", "epan/conversation.c", 241 , "count < 8"))));
242 | }
243 | return elements[count].conversation_type_val;
244 | }
245 |
246 | /* Create a string based on element types. */
247 | static char*
248 | conversation_element_list_name(wmem_allocator_t *allocator, conversation_element_t *elements) {
249 | char *sep = "";
250 | wmem_strbuf_t *conv_hash_group = wmem_strbuf_new(allocator, "");
251 | size_t element_count = conversation_element_count(elements);
252 | for (size_t i = 0; i < element_count; i++) {
253 | conversation_element_t *cur_el = &elements[i];
254 | DISSECTOR_ASSERT(cur_el->type < array_length(type_names))((void) ((cur_el->type < (sizeof (type_names) / sizeof ( type_names)[0])) ? (void)0 : (proto_report_dissector_bug("%s:%u: failed assertion \"%s\"" , "epan/conversation.c", 254, "cur_el->type < (sizeof (type_names) / sizeof (type_names)[0])" ))));
255 | wmem_strbuf_append_printf(conv_hash_group, "%s%s", sep, type_names[cur_el->type]);
256 | sep = ",";
257 | }
258 | return wmem_strbuf_finalize(conv_hash_group);
259 | }
260 |
261 | #if 0 // debugging
262 | static char* conversation_element_list_values(conversation_element_t *elements) {
263 | char *sep = "";
264 | GString *value_str = g_string_new("");
265 | size_t element_count = conversation_element_count(elements);
266 | for (size_t i = 0; i < element_count; i++) {
267 | conversation_element_t *cur_el = &elements[i];
268 | g_string_append_printf(value_str, "%s%s=", sep, type_names[cur_el->type]);
269 | sep = ",";
270 | switch (cur_el->type) {
271 | case CE_CONVERSATION_TYPE:
272 | g_string_append_printf(value_str, "%d", cur_el->conversation_type_val);
273 | break;
274 | case CE_ADDRESS:
275 | {
276 | char *as = address_to_str(NULL((void*)0), &cur_el->addr_val);
277 | g_string_append(value_str, as)(__builtin_constant_p (as) ? __extension__ ({ const char * const __val = (as); g_string_append_len_inline (value_str, __val, ( __val != ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline (value_str, as , (gssize) -1));
278 | g_free(as)(__builtin_object_size ((as), 0) != ((size_t) - 1)) ? g_free_sized (as, __builtin_object_size ((as), 0)) : (g_free) (as);
279 | }
280 | break;
281 | case CE_PORT:
282 | g_string_append_printf(value_str, "%u", cur_el->port_val);
283 | break;
284 | case CE_STRING:
285 | g_string_append(value_str, cur_el->str_val)(__builtin_constant_p (cur_el->str_val) ? __extension__ ({ const char * const __val = (cur_el->str_val); g_string_append_len_inline (value_str, __val, (__val != ((void*)0)) ? (gssize) strlen ( ((__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline (value_str, cur_el->str_val, (gssize) -1));
286 | break;
287 | case CE_UINT:
288 | g_string_append_printf(value_str, "%u", cur_el->uint_val);
289 | break;
290 | case CE_UINT64:
291 | g_string_append_printf(value_str, "%" PRIu64"l" "u", cur_el->uint64_val);
292 | break;
293 | case CE_INT:
294 | g_string_append_printf(value_str, "%d", cur_el->int_val);
295 | break;
296 | case CE_INT64:
297 | g_string_append_printf(value_str, "%" PRId64"l" "d", cur_el->int64_val);
298 | break;
299 | case CE_BLOB:
300 | {
301 | size_t l;
302 | uint8_t const *p;
303 | for (l = cur_el->blob.len, p = cur_el->blob.val; l > 0; l--, p++)
304 | g_string_append_printf(value_str, "%02x", *p);
305 | }
306 | break;
307 | }
308 | }
309 | return g_string_free(value_str, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((value_str ), ((0))) : g_string_free_and_steal (value_str)) : (g_string_free ) ((value_str), ((0))));
310 | }
311 | #endif
312 |
313 | static bool_Bool
314 | is_no_addr2_key(conversation_element_t *key)
315 | {
316 | if (key[ADDR1_IDX].type == CE_ADDRESS && key[PORT1_IDX].type == CE_PORT
317 | && key[PORT2_NO_ADDR2_IDX].type == CE_PORT && key[ENDP_NO_ADDR2_IDX].type == CE_CONVERSATION_TYPE) {
318 | return true1;
319 | }
320 | return false0;
321 | }
322 |
323 | static bool_Bool
324 | is_no_port2_key(conversation_element_t *key)
325 | {
326 | if (key[ADDR1_IDX].type == CE_ADDRESS && key[PORT1_IDX].type == CE_PORT
327 | && key[ADDR2_IDX].type == CE_ADDRESS && key[ENDP_NO_PORT2_IDX].type == CE_CONVERSATION_TYPE) {
328 | return true1;
329 | }
330 | return false0;
331 | }
332 |
333 | static bool_Bool
334 | is_no_addr2_port2_key(conversation_element_t *key)
335 | {
336 | if (key[ADDR1_IDX].type == CE_ADDRESS && key[PORT1_IDX].type == CE_PORT
337 | && key[ENDP_NO_ADDR2_PORT2_IDX].type == CE_CONVERSATION_TYPE) {
338 | return true1;
339 | }
340 | return false0;
341 | }
342 |
343 | /*
344 | * Creates a new conversation with known endpoints based on a conversation
345 | * created with the CONVERSATION_TEMPLATE option while keeping the
346 | * conversation created with the CONVERSATION_TEMPLATE option so it can still
347 | * match future connections.
348 | *
349 | * Passing a pointer to a conversation whose options mask does not include
350 | * CONVERSATION_TEMPLATE or where the conversation's protocol type (ptype)
351 | * indicates a non-connection oriented protocol will return the conversation
352 | * without changes.
353 | *
354 | * addr2 and port2 are used in the function if their respective conversation
355 | * options bits are set (NO_ADDR2 and NO_PORT2).
356 | */
357 | static conversation_t *
358 | conversation_create_from_template(conversation_t *conversation, const address *addr2, const uint32_t port2)
359 | {
360 | conversation_type ctype = conversation_get_key_type(conversation->key_ptr);
361 | /*
362 | * Add a new conversation and keep the conversation template only if the
363 | * CONVERSATION_TEMPLATE bit is set for a connection oriented protocol.
364 | */
365 | if (conversation->options & CONVERSATION_TEMPLATE0x08 && ctype != CONVERSATION_UDP)
366 | {
367 | /*
368 | * Set up a new options mask where the conversation template bit and the
369 | * bits for absence of a second address and port pair have been removed.
370 | */
371 | conversation_t *new_conversation_from_template;
372 | unsigned options = conversation->options & ~(CONVERSATION_TEMPLATE0x08 | NO_ADDR20x01 | NO_PORT20x02);
373 |
374 | /*
375 | * Are both the NO_ADDR2 and NO_PORT2 wildcards set in the options mask?
376 | */
377 | if (conversation->options & NO_ADDR20x01 && conversation->options & NO_PORT20x02
378 | && is_no_addr2_port2_key(conversation->key_ptr))
379 | {
380 | /*
381 | * The conversation template was created without knowledge of both
382 | * the second address as well as the second port. Create a new
383 | * conversation with new 2nd address and 2nd port.
384 | */
385 | new_conversation_from_template =
386 | conversation_new(conversation->setup_frame,
387 | &conversation->key_ptr[ADDR1_IDX].addr_val, addr2,
388 | ctype, conversation->key_ptr[PORT1_IDX].port_val,
389 | port2, options);
390 | }
391 | else if (conversation->options & NO_PORT20x02 && is_no_port2_key(conversation->key_ptr))
392 | {
393 | /*
394 | * The conversation template was created without knowledge of port 2
395 | * only. Create a new conversation with new 2nd port.
396 | */
397 | new_conversation_from_template =
398 | conversation_new(conversation->setup_frame,
399 | &conversation->key_ptr[ADDR1_IDX].addr_val, &conversation->key_ptr[ADDR2_IDX].addr_val,
400 | ctype, conversation->key_ptr[PORT1_IDX].port_val,
401 | port2, options);
402 | }
403 | else if (conversation->options & NO_ADDR20x01 && is_no_addr2_key(conversation->key_ptr))
404 | {
405 | /*
406 | * The conversation template was created without knowledge of address
407 | * 2. Create a new conversation with new 2nd address.
408 | */
409 | new_conversation_from_template =
410 | conversation_new(conversation->setup_frame,
411 | &conversation->key_ptr[ADDR1_IDX].addr_val, addr2,
412 | ctype, conversation->key_ptr[PORT1_IDX].port_val,
413 | conversation->key_ptr[PORT2_NO_ADDR2_IDX].port_val, options);
414 | }
415 | else
416 | {
417 | /*
418 | * The CONVERSATION_TEMPLATE bit was set, but no other bit that the
419 | * CONVERSATION_TEMPLATE bit controls is active. Just return the old
420 | * conversation.
421 | */
422 | return conversation;
423 | }
424 |
425 | /*
426 | * Set the protocol dissector used for the template conversation as
427 | * the handler of the new conversation as well.
428 | */
429 | new_conversation_from_template->dissector_tree = conversation->dissector_tree;
430 |
431 | return new_conversation_from_template;
432 | }
433 | else
434 | {
435 | return conversation;
436 | }
437 | }
438 |
439 | /*
440 | * Compute the hash value for two given element lists if the match
441 | * is to be exact.
442 | */
443 | /* https://web.archive.org/web/20070615045827/http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx#existing
444 | * (formerly at http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx#existing)
445 | * One-at-a-Time hash
446 | */
447 | static unsigned
448 | conversation_hash_element_list(const void *v)
449 | {
450 | const conversation_element_t *element = (const conversation_element_t*)v;
451 | unsigned hash_val = 0;
452 |
453 | for (;;) {
454 | // XXX We could use a hash_arbitrary_bytes routine. Abuse add_address_to_hash in the mean time.
455 | address tmp_addr;
456 | switch (element->type) {
457 | case CE_ADDRESS:
458 | hash_val = add_address_to_hash(hash_val, &element->addr_val);
459 | break;
460 | case CE_PORT:
461 | tmp_addr.len = (int) sizeof(element->port_val);
462 | tmp_addr.data = &element->port_val;
463 | hash_val = add_address_to_hash(hash_val, &tmp_addr);
464 | break;
465 | case CE_STRING:
466 | tmp_addr.len = (int) strlen(element->str_val);
467 | tmp_addr.data = element->str_val;
468 | hash_val = add_address_to_hash(hash_val, &tmp_addr);
469 | break;
470 | case CE_UINT:
471 | tmp_addr.len = (int) sizeof(element->uint_val);
472 | tmp_addr.data = &element->uint_val;
473 | hash_val = add_address_to_hash(hash_val, &tmp_addr);
474 | break;
475 | case CE_UINT64:
476 | tmp_addr.len = (int) sizeof(element->uint64_val);
477 | tmp_addr.data = &element->uint64_val;
478 | hash_val = add_address_to_hash(hash_val, &tmp_addr);
479 | break;
480 | case CE_INT:
481 | tmp_addr.len = (int) sizeof(element->int_val);
482 | tmp_addr.data = &element->int_val;
483 | hash_val = add_address_to_hash(hash_val, &tmp_addr);
484 | break;
485 | case CE_INT64:
486 | tmp_addr.len = (int) sizeof(element->int64_val);
487 | tmp_addr.data = &element->int64_val;
488 | hash_val = add_address_to_hash(hash_val, &tmp_addr);
489 | break;
490 | case CE_BLOB:
491 | tmp_addr.len = (int) element->blob.len;
492 | tmp_addr.data = element->blob.val;
493 | hash_val = add_address_to_hash(hash_val, &tmp_addr);
494 | break;
495 | case CE_CONVERSATION_TYPE:
496 | tmp_addr.len = (int) sizeof(element->conversation_type_val);
497 | tmp_addr.data = &element->conversation_type_val;
498 | hash_val = add_address_to_hash(hash_val, &tmp_addr);
499 | goto done;
500 | break;
501 | }
502 | element++;
503 | }
504 |
505 | done:
506 | hash_val += ( hash_val << 3 );
507 | hash_val ^= ( hash_val >> 11 );
508 | hash_val += ( hash_val << 15 );
509 |
510 | return hash_val;
511 | }
512 |
513 | /*
514 | * Compare two conversation keys for an exact match.
515 | */
516 | static gboolean
517 | conversation_match_element_list(const void *v1, const void *v2)
518 | {
519 | const conversation_element_t *element1 = (const conversation_element_t*)v1;
520 | const conversation_element_t *element2 = (const conversation_element_t*)v2;
521 |
522 | for (;;) {
523 | if (element1->type != element2->type) {
524 | return FALSE(0);
525 | }
526 |
527 | switch (element1->type) {
528 | case CE_ADDRESS:
529 | if (!addresses_equal(&element1->addr_val, &element2->addr_val)) {
530 | return FALSE(0);
531 | }
532 | break;
533 | case CE_PORT:
534 | if (element1->port_val != element2->port_val) {
535 | return FALSE(0);
536 | }
537 | break;
538 | case CE_STRING:
539 | if (strcmp(element1->str_val, element2->str_val)) {
540 | return FALSE(0);
541 | }
542 | break;
543 | case CE_UINT:
544 | if (element1->uint_val != element2->uint_val) {
545 | return FALSE(0);
546 | }
547 | break;
548 | case CE_UINT64:
549 | if (element1->uint64_val != element2->uint64_val) {
550 | return FALSE(0);
551 | }
552 | break;
553 | case CE_INT:
554 | if (element1->int_val != element2->int_val) {
555 | return FALSE(0);
556 | }
557 | break;
558 | case CE_INT64:
559 | if (element1->int64_val != element2->int64_val) {
560 | return FALSE(0);
561 | }
562 | break;
563 | case CE_BLOB:
564 | if (element1->blob.len != element2->blob.len ||
565 | (element1->blob.len > 0 && memcmp(element1->blob.val, element2->blob.val, element1->blob.len) != 0)) {
566 | return FALSE(0);
567 | }
568 | break;
569 | case CE_CONVERSATION_TYPE:
570 | if (element1->conversation_type_val != element2->conversation_type_val) {
571 | return FALSE(0);
572 | }
573 | goto done;
574 | break;
575 | }
576 | element1++;
577 | element2++;
578 | }
579 |
580 | done:
581 | // Everything matched so far.
582 | return TRUE(!(0));
583 | }
584 |
585 | /**
586 | * Create a new hash tables for conversations.
587 | */
588 | void
589 | conversation_init(void)
590 | {
591 | /*
592 | * Free up any space allocated for conversation protocol data
593 | * areas.
594 | *
595 | * We can free the space, as the structures it contains are
596 | * pointed to by conversation data structures that were freed
597 | * above.
598 | */
599 | conversation_hashtable_element_list = wmem_map_new(wmem_epan_scope(), wmem_str_hash, g_str_equal);
600 |
601 | conversation_element_t exact_elements[EXACT_IDX_COUNT] = {
602 | { CE_ADDRESS, .addr_val = ADDRESS_INIT_NONE{AT_NONE, 0, ((void*)0), ((void*)0)} },
603 | { CE_PORT, .port_val = 0 },
604 | { CE_ADDRESS, .addr_val = ADDRESS_INIT_NONE{AT_NONE, 0, ((void*)0), ((void*)0)} },
605 | { CE_PORT, .port_val = 0 },
606 | { CE_CONVERSATION_TYPE, .conversation_type_val = CONVERSATION_NONE }
607 | };
608 | char *exact_map_key = conversation_element_list_name(wmem_epan_scope(), exact_elements);
609 | conversation_hashtable_exact_addr_port = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(),
610 | conversation_hash_element_list,
611 | conversation_match_element_list);
612 | wmem_map_insert(conversation_hashtable_element_list, wmem_strdup(wmem_epan_scope(), exact_map_key),
613 | conversation_hashtable_exact_addr_port);
614 |
615 | conversation_element_t addrs_elements[ADDRS_IDX_COUNT] = {
616 | { CE_ADDRESS, .addr_val = ADDRESS_INIT_NONE{AT_NONE, 0, ((void*)0), ((void*)0)} },
617 | { CE_ADDRESS, .addr_val = ADDRESS_INIT_NONE{AT_NONE, 0, ((void*)0), ((void*)0)} },
618 | { CE_CONVERSATION_TYPE, .conversation_type_val = CONVERSATION_NONE }
619 | };
620 | char *addrs_map_key = conversation_element_list_name(wmem_epan_scope(), addrs_elements);
621 | conversation_hashtable_exact_addr = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(),
622 | conversation_hash_element_list,
623 | conversation_match_element_list);
624 | wmem_map_insert(conversation_hashtable_element_list, wmem_strdup(wmem_epan_scope(), addrs_map_key),
625 | conversation_hashtable_exact_addr);
626 |
627 | conversation_element_t no_addr2_elements[NO_ADDR2_IDX_COUNT] = {
628 | { CE_ADDRESS, .addr_val = ADDRESS_INIT_NONE{AT_NONE, 0, ((void*)0), ((void*)0)} },
629 | { CE_PORT, .port_val = 0 },
630 | { CE_PORT, .port_val = 0 },
631 | { CE_CONVERSATION_TYPE, .conversation_type_val = CONVERSATION_NONE }
632 | };
633 | char *no_addr2_map_key = conversation_element_list_name(wmem_epan_scope(), no_addr2_elements);
634 | conversation_hashtable_no_addr2 = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(),
635 | conversation_hash_element_list,
636 | conversation_match_element_list);
637 | wmem_map_insert(conversation_hashtable_element_list, wmem_strdup(wmem_epan_scope(), no_addr2_map_key),
638 | conversation_hashtable_no_addr2);
639 |
640 | conversation_element_t no_port2_elements[NO_PORT2_IDX_COUNT] = {
641 | { CE_ADDRESS, .addr_val = ADDRESS_INIT_NONE{AT_NONE, 0, ((void*)0), ((void*)0)} },
642 | { CE_PORT, .port_val = 0 },
643 | { CE_ADDRESS, .addr_val = ADDRESS_INIT_NONE{AT_NONE, 0, ((void*)0), ((void*)0)} },
644 | { CE_CONVERSATION_TYPE, .conversation_type_val = CONVERSATION_NONE }
645 | };
646 | char *no_port2_map_key = conversation_element_list_name(wmem_epan_scope(), no_port2_elements);
647 | conversation_hashtable_no_port2 = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(),
648 | conversation_hash_element_list,
649 | conversation_match_element_list);
650 | wmem_map_insert(conversation_hashtable_element_list, wmem_strdup(wmem_epan_scope(), no_port2_map_key),
651 | conversation_hashtable_no_port2);
652 |
653 | conversation_element_t no_addr2_or_port2_elements[NO_ADDR2_PORT2_IDX_COUNT] = {
654 | { CE_ADDRESS, .addr_val = ADDRESS_INIT_NONE{AT_NONE, 0, ((void*)0), ((void*)0)} },
655 | { CE_PORT, .port_val = 0 },
656 | { CE_CONVERSATION_TYPE, .conversation_type_val = CONVERSATION_NONE }
657 | };
658 | char *no_addr2_or_port2_map_key = conversation_element_list_name(wmem_epan_scope(), no_addr2_or_port2_elements);
659 | conversation_hashtable_no_addr2_or_port2 = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(),
660 | conversation_hash_element_list,
661 | conversation_match_element_list);
662 | wmem_map_insert(conversation_hashtable_element_list, wmem_strdup(wmem_epan_scope(), no_addr2_or_port2_map_key),
663 | conversation_hashtable_no_addr2_or_port2);
664 |
665 | conversation_element_t id_elements[2] = {
666 | { CE_UINT, .uint_val = 0 },
667 | { CE_CONVERSATION_TYPE, .conversation_type_val = CONVERSATION_NONE }
668 | };
669 | char *id_map_key = conversation_element_list_name(wmem_epan_scope(), id_elements);
670 | conversation_hashtable_id = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(),
671 | conversation_hash_element_list,
672 | conversation_match_element_list);
673 | wmem_map_insert(conversation_hashtable_element_list, wmem_strdup(wmem_epan_scope(), id_map_key),
674 | conversation_hashtable_id);
675 |
676 | /*
677 | * Initialize the "deinterlacer" table, which is used as the basis for the
678 | * deinterlacing process, and in conjunction with the "anchor" tables
679 | *
680 | * Typically the elements are:
681 | * ETH address 1
682 | * ETH address 2
683 | * Interface id
684 | * VLAN id
685 | * not used yet
686 | *
687 | * By the time of implementation, these table is invoked through the
688 | * conversation_deinterlacing_key user preference.
689 | */
690 | conversation_element_t deinterlacer_elements[EXACT_IDX_COUNT+1] = {
691 | { CE_ADDRESS, .addr_val = ADDRESS_INIT_NONE{AT_NONE, 0, ((void*)0), ((void*)0)} },
692 | { CE_ADDRESS, .addr_val = ADDRESS_INIT_NONE{AT_NONE, 0, ((void*)0), ((void*)0)} },
693 | { CE_UINT, .port_val = 0 },
694 | { CE_UINT, .port_val = 0 },
695 | { CE_UINT, .uint_val = 0 },
696 | { CE_CONVERSATION_TYPE, .conversation_type_val = CONVERSATION_NONE }
697 | };
698 | char *deinterlacer_map_key = conversation_element_list_name(wmem_epan_scope(), deinterlacer_elements);
699 | conversation_hashtable_deinterlacer = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(),
700 | conversation_hash_element_list,
701 | conversation_match_element_list);
702 | wmem_map_insert(conversation_hashtable_element_list, wmem_strdup(wmem_epan_scope(), deinterlacer_map_key),
703 | conversation_hashtable_deinterlacer);
704 |
705 | /*
706 | * Initialize the "_anc" tables, which are very similar to their standard counterparts
707 | * but contain an additional "anchor" materialized as an integer. This value is supposed
708 | * to indicate a stream ID of the underlying protocol, thus attaching two conversations
709 | * of two protocols together.
710 | *
711 | * By the time of implementation, these table is invoked through the
712 | * conversation_deinterlacing_key user preference.
713 | */
714 | conversation_element_t exact_elements_anc[EXACT_IDX_COUNT+1] = {
715 | { CE_ADDRESS, .addr_val = ADDRESS_INIT_NONE{AT_NONE, 0, ((void*)0), ((void*)0)} },
716 | { CE_ADDRESS, .addr_val = ADDRESS_INIT_NONE{AT_NONE, 0, ((void*)0), ((void*)0)} },
717 | { CE_PORT, .port_val = 0 },
718 | { CE_PORT, .port_val = 0 },
719 | { CE_UINT, .uint_val = 0 },
720 | { CE_CONVERSATION_TYPE, .conversation_type_val = CONVERSATION_NONE }
721 | };
722 | char *exact_anc_map_key = conversation_element_list_name(wmem_epan_scope(), exact_elements_anc);
723 | conversation_hashtable_exact_addr_port_anc = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(),
724 | conversation_hash_element_list,
725 | conversation_match_element_list);
726 | wmem_map_insert(conversation_hashtable_element_list, wmem_strdup(wmem_epan_scope(), exact_anc_map_key),
727 | conversation_hashtable_exact_addr_port_anc);
728 |
729 | conversation_element_t addrs_elements_anc[ADDRS_IDX_COUNT+1] = {
730 | { CE_ADDRESS, .addr_val = ADDRESS_INIT_NONE{AT_NONE, 0, ((void*)0), ((void*)0)} },
731 | { CE_ADDRESS, .addr_val = ADDRESS_INIT_NONE{AT_NONE, 0, ((void*)0), ((void*)0)} },
732 | { CE_UINT, .uint_val = 0 },
733 | { CE_CONVERSATION_TYPE, .conversation_type_val = CONVERSATION_NONE }
734 | };
735 | char *addrs_anc_map_key = conversation_element_list_name(wmem_epan_scope(), addrs_elements_anc);
736 | conversation_hashtable_exact_addr_anc = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(),
737 | conversation_hash_element_list,
738 | conversation_match_element_list);
739 | wmem_map_insert(conversation_hashtable_element_list, wmem_strdup(wmem_epan_scope(), addrs_anc_map_key),
740 | conversation_hashtable_exact_addr_anc);
741 |
742 | conversation_element_t no_addr2_elements_anc[DEINTD_NO_PORT2_IDX_COUNT] = {
743 | { CE_ADDRESS, .addr_val = ADDRESS_INIT_NONE{AT_NONE, 0, ((void*)0), ((void*)0)} },
744 | { CE_PORT, .port_val = 0 },
745 | { CE_PORT, .port_val = 0 },
746 | { CE_UINT, .uint_val = 0 },
747 | { CE_CONVERSATION_TYPE, .conversation_type_val = CONVERSATION_NONE }
748 | };
749 | char *no_addr2_anc_map_key = conversation_element_list_name(wmem_epan_scope(), no_addr2_elements_anc);
750 | conversation_hashtable_no_addr2_anc = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(),
751 | conversation_hash_element_list,
752 | conversation_match_element_list);
753 | wmem_map_insert(conversation_hashtable_element_list, wmem_strdup(wmem_epan_scope(), no_addr2_anc_map_key),
754 | conversation_hashtable_no_addr2_anc);
755 |
756 | conversation_element_t no_port2_elements_anc[DEINTD_NO_PORT2_IDX_COUNT] = {
757 | { CE_ADDRESS, .addr_val = ADDRESS_INIT_NONE{AT_NONE, 0, ((void*)0), ((void*)0)} },
758 | { CE_ADDRESS, .addr_val = ADDRESS_INIT_NONE{AT_NONE, 0, ((void*)0), ((void*)0)} },
759 | { CE_PORT, .port_val = 0 },
760 | { CE_UINT, .uint_val = 0 },
761 | { CE_CONVERSATION_TYPE, .conversation_type_val = CONVERSATION_NONE }
762 | };
763 | char *no_port2_anc_map_key = conversation_element_list_name(wmem_epan_scope(), no_port2_elements_anc);
764 | conversation_hashtable_no_port2_anc = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(),
765 | conversation_hash_element_list,
766 | conversation_match_element_list);
767 | wmem_map_insert(conversation_hashtable_element_list, wmem_strdup(wmem_epan_scope(), no_port2_anc_map_key),
768 | conversation_hashtable_no_port2_anc);
769 |
770 | conversation_element_t no_addr2_or_port2_elements_anc[DEINTD_NO_ADDR2_PORT2_IDX_COUNT] = {
771 | { CE_ADDRESS, .addr_val = ADDRESS_INIT_NONE{AT_NONE, 0, ((void*)0), ((void*)0)} },
772 | { CE_PORT, .port_val = 0 },
773 | { CE_UINT, .uint_val = 0 },
774 | { CE_CONVERSATION_TYPE, .conversation_type_val = CONVERSATION_NONE }
775 | };
776 | char *no_addr2_or_port2_anc_map_key = conversation_element_list_name(wmem_epan_scope(), no_addr2_or_port2_elements_anc);
777 | conversation_hashtable_no_addr2_or_port2_anc = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(),
778 | conversation_hash_element_list,
779 | conversation_match_element_list);
780 | wmem_map_insert(conversation_hashtable_element_list, wmem_strdup(wmem_epan_scope(), no_addr2_or_port2_anc_map_key),
781 | conversation_hashtable_no_addr2_or_port2_anc);
782 |
783 | conversation_element_t err_pkts_elements[ERR_PKTS_COUNT] = {
784 | { CE_UINT, .uint_val = 0 },
785 | { CE_UINT, .uint_val = 0 },
786 | { CE_CONVERSATION_TYPE, .conversation_type_val = CONVERSATION_NONE }
787 | };
788 | char *err_pkts_map_key = conversation_element_list_name(wmem_epan_scope(), err_pkts_elements);
789 | conversation_hashtable_err_pkts = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(),
790 | conversation_hash_element_list,
791 | conversation_match_element_list);
792 | wmem_map_insert(conversation_hashtable_element_list, wmem_strdup(wmem_epan_scope(), err_pkts_map_key),
793 | conversation_hashtable_err_pkts);
794 |
795 | }
796 |
797 | /**
798 | * Initialize some variables every time a file is loaded or re-loaded.
799 | */
800 | void
801 | conversation_epan_reset(void)
802 | {
803 | /*
804 | * Start the conversation indices over at 0.
805 | */
806 | new_index = 0;
807 | }
808 |
809 | /*
810 | * Does the right thing when inserting into one of the conversation hash tables,
811 | * taking into account ordering and hash chains and all that good stuff.
812 | *
813 | * Mostly adapted from the old conversation_new().
814 | */
815 | static void
816 | conversation_insert_into_hashtable(wmem_map_t *hashtable, conversation_t *conv)
817 | {
818 | conversation_t *chain_head, *chain_tail, *cur, *prev;
819 |
820 | chain_head = (conversation_t *)wmem_map_lookup(hashtable, conv->key_ptr);
821 |
822 | if (NULL((void*)0)==chain_head) {
823 | /* New entry */
824 | conv->next = NULL((void*)0);
825 | conv->last = conv;
826 |
827 | wmem_map_insert(hashtable, conv->key_ptr, conv);
828 | DPRINT(("created a new conversation chain"))(void)0;
829 | }
830 | else {
831 | /* There's an existing chain for this key */
832 | DPRINT(("there's an existing conversation chain"))(void)0;
833 |
834 | chain_tail = chain_head->last;
835 |
836 | if (conv->setup_frame >= chain_tail->setup_frame) {
837 | /* This convo belongs at the end of the chain */
838 | conv->next = NULL((void*)0);
839 | conv->last = NULL((void*)0);
840 | chain_tail->next = conv;
841 | chain_head->last = conv;
842 | }
843 | else {
844 | /* Loop through the chain to find the right spot */
845 | cur = chain_head;
846 | prev = NULL((void*)0);
847 |
848 | for (; (conv->setup_frame > cur->setup_frame) && cur->next; prev=cur, cur=cur->next)
849 | ;
850 |
851 | if (NULL((void*)0)==prev) {
852 | /* Changing the head of the chain */
853 | conv->next = chain_head;
854 | conv->last = chain_tail;
855 | chain_head->last = NULL((void*)0);
856 | wmem_map_insert(hashtable, conv->key_ptr, conv);
857 | }
858 | else {
859 | /* Inserting into the middle of the chain */
860 | conv->next = cur;
861 | conv->last = NULL((void*)0);
862 | prev->next = conv;
863 | }
864 | }
865 | }
866 | }
867 |
868 | /*
869 | * Does the right thing when removing from one of the conversation hash tables,
870 | * taking into account ordering and hash chains and all that good stuff.
871 | */
872 | static void
873 | conversation_remove_from_hashtable(wmem_map_t *hashtable, conversation_t *conv)
874 | {
875 | conversation_t *chain_head, *cur, *prev;
876 |
877 | chain_head = (conversation_t *)wmem_map_lookup(hashtable, conv->key_ptr);
878 |
879 | if (conv == chain_head) {
880 | /* We are currently the front of the chain */
881 | if (NULL((void*)0) == conv->next) {
882 | /* We are the only conversation in the chain, no need to
883 | * update next pointer, but do not call
884 | * wmem_map_remove() either because the conv data
885 | * will be re-inserted. */
886 | wmem_map_steal(hashtable, conv->key_ptr);
887 | }
888 | else {
889 | /* Update the head of the chain */
890 | chain_head = conv->next;
891 | chain_head->last = conv->last;
892 |
893 | if (conv->latest_found == conv)
894 | chain_head->latest_found = NULL((void*)0);
895 | else
896 | chain_head->latest_found = conv->latest_found;
897 |
898 | wmem_map_insert(hashtable, chain_head->key_ptr, chain_head);
899 | }
900 | }
901 | else {
902 | /* We are not the front of the chain. Loop through to find us.
903 | * Start loop at chain_head->next rather than chain_head because
904 | * we already know we're not at the head. */
905 | cur = chain_head->next;
906 | prev = chain_head;
907 |
908 | for (; (cur != conv) && cur->next; prev=cur, cur=cur->next)
909 | ;
910 |
911 | if (cur != conv) {
912 | /* XXX: Conversation not found. Wrong hashtable? */
913 | return;
914 | }
915 |
916 | prev->next = conv->next;
917 |
918 | if (NULL((void*)0) == conv->next) {
919 | /* We're at the very end of the list. */
920 | chain_head->last = prev;
921 | }
922 |
923 | if (chain_head->latest_found == conv)
924 | chain_head->latest_found = prev;
925 | }
926 | }
927 |
928 | conversation_t *conversation_new_full(const uint32_t setup_frame, conversation_element_t *elements)
929 | {
930 | DISSECTOR_ASSERT(elements)((void) ((elements) ? (void)0 : (proto_report_dissector_bug("%s:%u: failed assertion \"%s\"" , "epan/conversation.c", 930, "elements"))));
931 |
932 | char *el_list_map_key = conversation_element_list_name(wmem_epan_scope(), elements);
933 | wmem_map_t *el_list_map = (wmem_map_t *) wmem_map_lookup(conversation_hashtable_element_list, el_list_map_key);
934 | if (!el_list_map) {
935 | el_list_map = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), conversation_hash_element_list,
936 | conversation_match_element_list);
937 | wmem_map_insert(conversation_hashtable_element_list, wmem_strdup(wmem_epan_scope(), el_list_map_key), el_list_map);
938 | }
939 |
940 | size_t element_count = conversation_element_count(elements);
941 | conversation_element_t *conv_key = wmem_memdup(wmem_file_scope(), elements, sizeof(conversation_element_t) * element_count);
942 | for (size_t i = 0; i < element_count; i++) {
943 | if (conv_key[i].type == CE_ADDRESS) {
944 | copy_address_wmem(wmem_file_scope(), &conv_key[i].addr_val, &elements[i].addr_val);
945 | } else if (conv_key[i].type == CE_STRING) {
946 | conv_key[i].str_val = wmem_strdup(wmem_file_scope(), elements[i].str_val);
947 | } else if (conv_key[i].type == CE_BLOB) {
948 | conv_key[i].blob.val = wmem_memdup(wmem_file_scope(), elements[i].blob.val, elements[i].blob.len);
949 | }
950 | }
951 |
952 | conversation_t *conversation = wmem_new0(wmem_file_scope(), conversation_t)((conversation_t*)wmem_alloc0((wmem_file_scope()), sizeof(conversation_t )));
953 | conversation->conv_index = new_index;
954 | conversation->setup_frame = conversation->last_frame = setup_frame;
955 |
956 | new_index++;
957 |
958 | conversation->key_ptr = conv_key;
959 | conversation_insert_into_hashtable(el_list_map, conversation);
960 | return conversation;
961 | }
962 |
963 | /*
964 | * Given two address/port pairs for a packet, create a new conversation
965 | * to contain packets between those address/port pairs.
966 | *
967 | * The options field is used to specify whether the address 2 value
968 | * and/or port 2 value are not given and any value is acceptable
969 | * when searching for this conversation.
970 | */
971 | conversation_t *
972 | conversation_new(const uint32_t setup_frame, const address *addr1, const address *addr2,
973 | const conversation_type ctype, const uint32_t port1, const uint32_t port2, const unsigned options)
974 | {
975 | /*
976 | DISSECTOR_ASSERT(!(options | CONVERSATION_TEMPLATE) || ((options | (NO_ADDR2 | NO_PORT2 | NO_PORT2_FORCE))) &&
977 | "A conversation template may not be constructed without wildcard options");
978 | */
979 | wmem_map_t* hashtable;
980 | conversation_t *conversation = NULL((void*)0);
981 | /*
982 | * Verify that the correct options are used, if any.
983 | */
984 | DISSECTOR_ASSERT_HINT(!(options & NO_MASK_B), "Use NO_ADDR2 and/or NO_PORT2 or NO_PORT2_FORCE as option")((void) ((!(options & 0xFFFF0000)) ? (void)0 : (proto_report_dissector_bug ("%s:%u: failed assertion \"%s\" (%s)", "epan/conversation.c" , 984, "!(options & 0xFFFF0000)", "Use NO_ADDR2 and/or NO_PORT2 or NO_PORT2_FORCE as option" ))));
985 |
986 | #ifdef DEBUG_CONVERSATION
987 | char *addr1_str, *addr2_str;
988 | if (addr1 == NULL((void*)0)) {
989 | /*
990 | * No address 1.
991 | */
992 | if (options & NO_ADDR20x01) {
993 | /*
994 | * Neither address 1 nor address 2.
995 | */
996 | if (options & NO_PORT20x02) {
997 | /*
998 | * Port 1 but not port 2.
999 | */
1000 | DPRINT(("creating conversation for frame #%u: ID %u (ctype=%d)",(void)0
1001 | setup_frame, port1, ctype))(void)0;
1002 | } else {
1003 | /*
1004 | * Ports 1 and 2.
1005 | */
1006 | DPRINT(("creating conversation for frame #%u: %u -> %u (ctype=%d)",(void)0
1007 | setup_frame, port1, port2, ctype))(void)0;
1008 | }
1009 | } else {
1010 | /*
1011 | * Address 2 but not address 1.
1012 | */
1013 | addr2_str = address_to_str(NULL((void*)0), addr2);
1014 | if (options & NO_PORT20x02) {
1015 | /*
1016 | * Port 1 but not port 2.
1017 | */
1018 | DPRINT(("creating conversation for frame #%u: ID %u, address %s (ctype=%d)",(void)0
1019 | setup_frame, port1, addr2_str, ctype))(void)0;
1020 | } else {
1021 | /*
1022 | * Ports 1 and 2.
1023 | */
1024 | DPRINT(("creating conversation for frame #%u: %u -> %s:%u (ctype=%d)",(void)0
1025 | setup_frame, port1, addr2_str, port2, ctype))(void)0;
1026 | }
1027 | wmem_free(NULL((void*)0), addr2_str);
1028 | }
1029 | } else {
1030 | /*
1031 | * Address 1.
1032 | */
1033 | addr1_str = address_to_str(NULL((void*)0), addr1);
1034 | if (options & NO_ADDR20x01) {
1035 | /*
1036 | * Address 1 but no address 2.
1037 | */
1038 | if (options & NO_PORT20x02) {
1039 | /*
1040 | * Port 1 but not port 2.
1041 | */
1042 | DPRINT(("creating conversation for frame #%u: %s:%u (ctype=%d)",(void)0
1043 | setup_frame, addr1_str, port1, ctype))(void)0;
1044 | } else {
1045 | /*
1046 | * Ports 1 and 2.
1047 | */
1048 | DPRINT(("creating conversation for frame #%u: %s:%u -> %u (ctype=%d)",(void)0
1049 | setup_frame, addr1_str, port1, port2, ctype))(void)0;
1050 | }
1051 | } else {
1052 | /*
1053 | * Addresses 1 and 2.
1054 | */
1055 | addr2_str = address_to_str(NULL((void*)0), addr2);
1056 | if (options & NO_PORT20x02) {
1057 | /*
1058 | * Port 1 but not port 2.
1059 | */
1060 | DPRINT(("creating conversation for frame #%u: %s:%u -> %s (ctype=%d)",(void)0
1061 | setup_frame, addr1_str, port1, addr2_str, ctype))(void)0;
1062 | } else if (options & NO_PORTS0x010) {
1063 | /*
1064 | * No Ports.
1065 | */
1066 | DPRINT(("creating conversation for frame #%u: %s -> %s (ctype=%d)",(void)0
1067 | setup_frame, addr1_str, addr2_str, ctype))(void)0;
1068 | } else {
1069 | /*
1070 | * Ports 1 and 2.
1071 | */
1072 | DPRINT(("creating conversation for frame #%u: %s:%u -> %s:%u (ctype=%d)",(void)0
1073 | setup_frame, addr1_str, port1, addr2_str, port2, ctype))(void)0;
1074 | }
1075 | wmem_free(NULL((void*)0), addr2_str);
1076 | }
1077 | wmem_free(NULL((void*)0), addr1_str);
1078 | }
1079 | #endif
1080 |
1081 | // Always allocate an "exact"-sized key in case we call conversation_set_port2
1082 | // or conversation_set_addr2 later.
1083 | conversation_element_t *new_key = wmem_alloc(wmem_file_scope(), sizeof(conversation_element_t) * EXACT_IDX_COUNT);
1084 | size_t addr2_idx = 0;
1085 | size_t port2_idx = 0;
1086 | size_t endp_idx;
1087 |
1088 | new_key[ADDR1_IDX].type = CE_ADDRESS;
1089 | if (addr1 != NULL((void*)0)) {
1090 | copy_address_wmem(wmem_file_scope(), &new_key[ADDR1_IDX].addr_val, addr1);
1091 | } else {
1092 | clear_address(&new_key[ADDR1_IDX].addr_val);
1093 | }
1094 |
1095 | if (!(options & NO_PORTS0x010)) {
1096 | new_key[PORT1_IDX].type = CE_PORT;
1097 | new_key[PORT1_IDX].port_val = port1;
1098 | }
1099 |
1100 | if (options & NO_ADDR20x01) {
1101 | if (options & (NO_PORT20x02|NO_PORT2_FORCE0x04)) {
1102 | hashtable = conversation_hashtable_no_addr2_or_port2;
1103 | endp_idx = ENDP_NO_ADDR2_PORT2_IDX;
1104 | } else {
1105 | hashtable = conversation_hashtable_no_addr2;
1106 | port2_idx = PORT2_NO_ADDR2_IDX;
1107 | endp_idx = ENDP_NO_ADDR2_IDX;
1108 | }
1109 | } else {
1110 | if (options & (NO_PORT20x02|NO_PORT2_FORCE0x04)) {
1111 | hashtable = conversation_hashtable_no_port2;
1112 | addr2_idx = ADDR2_IDX;
1113 | endp_idx = ENDP_NO_PORT2_IDX;
1114 | } else if (options & NO_PORTS0x010) {
1115 | hashtable = conversation_hashtable_exact_addr;
1116 | addr2_idx = PORT1_IDX;
1117 | endp_idx = ENDP_NO_PORTS_IDX;
1118 | } else {
1119 | hashtable = conversation_hashtable_exact_addr_port;
1120 | addr2_idx = ADDR2_IDX;
1121 | port2_idx = PORT2_IDX;
1122 | endp_idx = ENDP_EXACT_IDX;
1123 | }
1124 | }
1125 |
1126 | if (addr2_idx) {
1127 | new_key[addr2_idx].type = CE_ADDRESS;
1128 | if (addr2 != NULL((void*)0)) {
1129 | copy_address_wmem(wmem_file_scope(), &new_key[addr2_idx].addr_val, addr2);
1130 | } else {
1131 | clear_address(&new_key[addr2_idx].addr_val);
1132 | }
1133 | }
1134 |
1135 | if (port2_idx) {
1136 | new_key[port2_idx].type = CE_PORT;
1137 | new_key[port2_idx].port_val = port2;
1138 | }
1139 |
1140 | new_key[endp_idx].type = CE_CONVERSATION_TYPE;
1141 | new_key[endp_idx].conversation_type_val = ctype;
1142 |
1143 | conversation = wmem_new0(wmem_file_scope(), conversation_t)((conversation_t*)wmem_alloc0((wmem_file_scope()), sizeof(conversation_t )));
1144 |
1145 | conversation->conv_index = new_index;
1146 | conversation->setup_frame = conversation->last_frame = setup_frame;
1147 |
1148 | /* set the options and key pointer */
1149 | conversation->options = options;
1150 | conversation->key_ptr = new_key;
1151 |
1152 | new_index++;
1153 |
1154 | DINDENT()(void)0;
1155 | conversation_insert_into_hashtable(hashtable, conversation);
1156 | DENDENT()(void)0;
1157 |
1158 | return conversation;
1159 | }
1160 |
1161 | conversation_t *
1162 | conversation_new_strat(const packet_info *pinfo, const conversation_type ctype, const unsigned options)
1163 | {
1164 | conversation_t *conversation = NULL((void*)0);
1165 | bool_Bool is_ordinary_conv = true1;
1166 |
1167 | if(is_deinterlacing_supported(pinfo)) {
1168 | conversation_t *underlying_conv = find_conversation_deinterlacer_pinfo(pinfo);
1169 | if(underlying_conv) {
1170 | is_ordinary_conv = false0;
1171 | conversation = conversation_new_deinterlaced(pinfo->num, &pinfo->src, &pinfo->dst, ctype,
1172 | pinfo->srcport, pinfo->destport, underlying_conv->conv_index, options);
1173 | }
1174 | }
1175 |
1176 | if(is_ordinary_conv) {
1177 | conversation = conversation_new(pinfo->num, &pinfo->src, &pinfo->dst, ctype, pinfo->srcport, pinfo->destport, options);
1178 | }
1179 |
1180 | return conversation;
1181 | }
1182 |
1183 | conversation_t *
1184 | conversation_new_strat_xtd(const packet_info *pinfo, const uint32_t setup_frame, const address *addr1, const address *addr2,
1185 | const conversation_type ctype, const uint32_t port1, const uint32_t port2, const unsigned options)
1186 | {
1187 | conversation_t *conversation = NULL((void*)0);
1188 | bool_Bool is_ordinary_conv = true1;
1189 |
1190 | if(is_deinterlacing_supported(pinfo)) {
1191 | conversation_t *underlying_conv = find_conversation_deinterlacer_pinfo(pinfo);
1192 | if(underlying_conv) {
1193 | is_ordinary_conv = false0;
1194 | conversation = conversation_new_deinterlaced(setup_frame, addr1, addr2, ctype,
1195 | port1, port2, underlying_conv->conv_index, options);
1196 | }
1197 | }
1198 |
1199 | if(is_ordinary_conv) {
1200 | conversation = conversation_new(setup_frame, addr1, addr2, ctype, port1, port2, options);
1201 | }
1202 |
1203 | return conversation;
1204 | }
1205 |
1206 | conversation_t *
1207 | conversation_new_by_id(const uint32_t setup_frame, const conversation_type ctype, const uint32_t id)
1208 | {
1209 | conversation_t *conversation = wmem_new0(wmem_file_scope(), conversation_t)((conversation_t*)wmem_alloc0((wmem_file_scope()), sizeof(conversation_t )));
1210 | conversation->conv_index = new_index;
1211 | conversation->setup_frame = conversation->last_frame = setup_frame;
1212 |
1213 | new_index++;
1214 |
1215 | conversation_element_t *elements = wmem_alloc(wmem_file_scope(), sizeof(conversation_element_t) * 2);
1216 | elements[0].type = CE_UINT;
1217 | elements[0].uint_val = id;
1218 | elements[1].type = CE_CONVERSATION_TYPE;
1219 | elements[1].conversation_type_val = ctype;
1220 | conversation->key_ptr = elements;
1221 | conversation_insert_into_hashtable(conversation_hashtable_id, conversation);
1222 |
1223 | return conversation;
1224 | }
1225 |
1226 | conversation_t *
1227 | conversation_new_err_pkts(const uint32_t setup_frame, const conversation_type ctype, const uint32_t id, const uint32_t rid)
1228 | {
1229 | conversation_t *conversation = wmem_new0(wmem_file_scope(), conversation_t)((conversation_t*)wmem_alloc0((wmem_file_scope()), sizeof(conversation_t )));
1230 | conversation->conv_index = new_index;
1231 | conversation->setup_frame = conversation->last_frame = setup_frame;
1232 |
1233 | new_index++;
1234 |
1235 | conversation_element_t *elements = wmem_alloc(wmem_file_scope(), sizeof(conversation_element_t) * 3);
1236 | elements[0].type = CE_UINT;
1237 | elements[0].uint_val = id;
1238 | elements[1].type = CE_UINT;
1239 | elements[1].uint_val = rid;
1240 | elements[2].type = CE_CONVERSATION_TYPE;
1241 | elements[2].conversation_type_val = ctype;
1242 | conversation->key_ptr = elements;
1243 | conversation_insert_into_hashtable(conversation_hashtable_err_pkts, conversation);
1244 |
1245 | return conversation;
1246 | }
1247 |
1248 | conversation_t *
1249 | conversation_new_deinterlacer(const uint32_t setup_frame, const address *addr1, const address *addr2,
1250 | const conversation_type ctype, const uint32_t key1, const uint32_t key2, const uint32_t key3)
1251 | {
1252 |
1253 | conversation_t *conversation = wmem_new0(wmem_file_scope(), conversation_t)((conversation_t*)wmem_alloc0((wmem_file_scope()), sizeof(conversation_t )));
1254 | conversation->conv_index = new_index;
1255 | conversation->setup_frame = conversation->last_frame = setup_frame;
1256 |
1257 | conversation_element_t *new_key = wmem_alloc(wmem_file_scope(), sizeof(conversation_element_t) * (DEINTR_ENDP_IDX+1));
1258 |
1259 | new_key[DEINTR_ADDR1_IDX].type = CE_ADDRESS;
1260 | if (addr1 != NULL((void*)0)) {
1261 | copy_address_wmem(wmem_file_scope(), &new_key[DEINTR_ADDR1_IDX].addr_val, addr1);
1262 | }
1263 | else {
1264 | clear_address(&new_key[DEINTR_ADDR1_IDX].addr_val);
1265 | }
1266 |
1267 | new_key[DEINTR_ADDR2_IDX].type = CE_ADDRESS;
1268 | if (addr2 != NULL((void*)0)) {
1269 | copy_address_wmem(wmem_file_scope(), &new_key[DEINTR_ADDR2_IDX].addr_val, addr2);
1270 | }
1271 | else {
1272 | clear_address(&new_key[DEINTR_ADDR2_IDX].addr_val);
1273 | }
1274 |
1275 | new_key[DEINTR_KEY1_IDX].type = CE_UINT;
1276 | new_key[DEINTR_KEY1_IDX].uint_val = key1;
1277 |
1278 | new_key[DEINTR_KEY2_IDX].type = CE_UINT;
1279 | new_key[DEINTR_KEY2_IDX].uint_val = key2;
1280 |
1281 | new_key[DEINTR_KEY3_IDX].type = CE_UINT;
1282 | new_key[DEINTR_KEY3_IDX].uint_val = key3;
1283 |
1284 | new_key[DEINTR_ENDP_IDX].type = CE_CONVERSATION_TYPE;
1285 | new_key[DEINTR_ENDP_IDX].conversation_type_val = ctype;
1286 |
1287 | conversation->key_ptr = new_key;
1288 |
1289 | new_index++;
1290 |
1291 | conversation_insert_into_hashtable(conversation_hashtable_deinterlacer, conversation);
1292 |
1293 | return conversation;
1294 | }
1295 |
1296 | conversation_t *
1297 | conversation_new_deinterlaced(const uint32_t setup_frame, const address *addr1, const address *addr2,
1298 | const conversation_type ctype, const uint32_t port1, const uint32_t port2, const uint32_t anchor, const unsigned options)
1299 | {
1300 |
1301 | conversation_t *conversation = wmem_new0(wmem_file_scope(), conversation_t)((conversation_t*)wmem_alloc0((wmem_file_scope()), sizeof(conversation_t )));
1302 | conversation->conv_index = new_index;
1303 | conversation->setup_frame = conversation->last_frame = setup_frame;
1304 |
1305 | if (options & NO_PORTS0x010) {
1306 | conversation_element_t *new_key = wmem_alloc(wmem_file_scope(), sizeof(conversation_element_t) * (DEINTD_ENDP_NO_PORTS_IDX+2));
1307 |
1308 | new_key[DEINTD_ADDR1_IDX].type = CE_ADDRESS;
1309 | if (addr1 != NULL((void*)0)) {
1310 | copy_address_wmem(wmem_file_scope(), &new_key[DEINTD_ADDR1_IDX].addr_val, addr1);
1311 | }
1312 | else {
1313 | clear_address(&new_key[DEINTD_ADDR1_IDX].addr_val);
1314 | }
1315 |
1316 | new_key[DEINTD_ADDR2_IDX].type = CE_ADDRESS;
1317 | if (addr2 != NULL((void*)0)) {
1318 | copy_address_wmem(wmem_file_scope(), &new_key[DEINTD_ADDR2_IDX].addr_val, addr2);
1319 | }
1320 | else {
1321 | clear_address(&new_key[DEINTD_ADDR2_IDX].addr_val);
1322 | }
1323 |
1324 | new_key[DEINTD_ENDP_NO_PORTS_IDX].type = CE_UINT;
1325 | new_key[DEINTD_ENDP_NO_PORTS_IDX].uint_val = anchor;
1326 |
1327 | new_key[DEINTD_ENDP_NO_PORTS_IDX+ 1].type = CE_CONVERSATION_TYPE;
1328 | new_key[DEINTD_ENDP_NO_PORTS_IDX+ 1].conversation_type_val = ctype;
1329 |
1330 | // set the options and key pointer
1331 | conversation->options = options;
1332 | conversation->key_ptr = new_key;
1333 |
1334 | new_index++;
1335 |
1336 | conversation_insert_into_hashtable(conversation_hashtable_exact_addr_anc, conversation);
1337 |
1338 | return conversation;
1339 | }
1340 | else if (options & NO_ADDR20x01) {
1341 | if (options & NO_PORT20x02) {
1342 |
1343 | conversation_element_t *new_key = wmem_alloc(wmem_file_scope(), sizeof(conversation_element_t) * (DEINTD_NO_ADDR2_PORT2_IDX_COUNT+1));
1344 |
1345 | new_key[DEINTD_ADDR1_IDX].type = CE_ADDRESS;
1346 | if (addr1 != NULL((void*)0)) {
1347 | copy_address_wmem(wmem_file_scope(), &new_key[DEINTD_ADDR1_IDX].addr_val, addr1);
1348 | }
1349 | else {
1350 | clear_address(&new_key[DEINTD_ADDR1_IDX].addr_val);
1351 | }
1352 |
1353 | new_key[DEINTD_PORT1_IDX-1].type = CE_PORT;
1354 | new_key[DEINTD_PORT1_IDX-1].port_val = port1;
1355 |
1356 | new_key[DEINTD_NO_ADDR2_PORT2_IDX_COUNT-2].type = CE_UINT;
1357 | new_key[DEINTD_NO_ADDR2_PORT2_IDX_COUNT-2].uint_val = anchor;
1358 |
1359 | new_key[DEINTD_NO_ADDR2_PORT2_IDX_COUNT-1].type = CE_CONVERSATION_TYPE;
1360 | new_key[DEINTD_NO_ADDR2_PORT2_IDX_COUNT-1].conversation_type_val = ctype;
1361 |
1362 | // set the options and key pointer
1363 | conversation->options = options;
1364 | conversation->key_ptr = new_key;
1365 |
1366 | new_index++;
1367 |
1368 | conversation_insert_into_hashtable(conversation_hashtable_no_addr2_or_port2_anc, conversation);
1369 |
1370 | return conversation;
1371 | }
1372 |
1373 | else {
1374 | conversation_element_t *new_key = wmem_alloc(wmem_file_scope(), sizeof(conversation_element_t) * (DEINTD_NO_ADDR2_IDX_COUNT+1));
1375 |
1376 | new_key[DEINTD_ADDR1_IDX].type = CE_ADDRESS;
1377 | if (addr1 != NULL((void*)0)) {
1378 | copy_address_wmem(wmem_file_scope(), &new_key[DEINTD_ADDR1_IDX].addr_val, addr1);
1379 | }
1380 | else {
1381 | clear_address(&new_key[DEINTD_ADDR1_IDX].addr_val);
1382 | }
1383 |
1384 | new_key[DEINTD_PORT1_IDX-1].type = CE_PORT;
1385 | new_key[DEINTD_PORT1_IDX-1].port_val = port1;
1386 |
1387 | new_key[DEINTD_PORT2_IDX-1].type = CE_PORT;
1388 | new_key[DEINTD_PORT2_IDX-1].port_val = port2;
1389 |
1390 | new_key[DEINTD_NO_ADDR2_IDX_COUNT-2].type = CE_UINT;
1391 | new_key[DEINTD_NO_ADDR2_IDX_COUNT-2].uint_val = anchor;
1392 |
1393 | new_key[DEINTD_NO_ADDR2_IDX_COUNT-1].type = CE_CONVERSATION_TYPE;
1394 | new_key[DEINTD_NO_ADDR2_IDX_COUNT-1].conversation_type_val = ctype;
1395 |
1396 | // set the options and key pointer
1397 | conversation->options = options;
1398 | conversation->key_ptr = new_key;
1399 |
1400 | new_index++;
1401 |
1402 | conversation_insert_into_hashtable(conversation_hashtable_no_addr2_anc, conversation);
1403 |
1404 | return conversation;
1405 | }
1406 | }
1407 | else if (options & NO_PORT20x02) {
1408 | conversation_element_t *new_key = wmem_alloc(wmem_file_scope(), sizeof(conversation_element_t) * (DEINTD_EXACT_IDX_COUNT+1));
1409 |
1410 | new_key[DEINTD_ADDR1_IDX].type = CE_ADDRESS;
1411 | if (addr1 != NULL((void*)0)) {
1412 | copy_address_wmem(wmem_file_scope(), &new_key[DEINTD_ADDR1_IDX].addr_val, addr1);
1413 | }
1414 | else {
1415 | clear_address(&new_key[DEINTD_ADDR1_IDX].addr_val);
1416 | }
1417 |
1418 | new_key[DEINTD_ADDR2_IDX].type = CE_ADDRESS;
1419 | if (addr2 != NULL((void*)0)) {
1420 | copy_address_wmem(wmem_file_scope(), &new_key[DEINTD_ADDR2_IDX].addr_val, addr2);
1421 | }
1422 | else {
1423 | clear_address(&new_key[DEINTD_ADDR2_IDX].addr_val);
1424 | }
1425 |
1426 | new_key[DEINTD_PORT1_IDX].type = CE_PORT;
1427 | new_key[DEINTD_PORT1_IDX].port_val = port1;
1428 |
1429 | new_key[DEINTD_PORT1_IDX + 1].type = CE_UINT;
1430 | new_key[DEINTD_PORT1_IDX + 1].uint_val = anchor;
1431 |
1432 | new_key[DEINTD_PORT1_IDX + 2].type = CE_CONVERSATION_TYPE;
1433 | new_key[DEINTD_PORT1_IDX + 2].conversation_type_val = ctype;
1434 |
1435 | // set the options and key pointer
1436 | conversation->options = options;
1437 | conversation->key_ptr = new_key;
1438 |
1439 | new_index++;
1440 |
1441 | conversation_insert_into_hashtable(conversation_hashtable_exact_addr_port_anc, conversation);
1442 |
1443 | return conversation;
1444 | }
1445 | else {
1446 | conversation_element_t *new_key = wmem_alloc(wmem_file_scope(), sizeof(conversation_element_t) * (DEINTD_EXACT_IDX_COUNT+2));
1447 |
1448 | new_key[DEINTD_ADDR1_IDX].type = CE_ADDRESS;
1449 | if (addr1 != NULL((void*)0)) {
1450 | copy_address_wmem(wmem_file_scope(), &new_key[DEINTD_ADDR1_IDX].addr_val, addr1);
1451 | }
1452 | else {
1453 | clear_address(&new_key[DEINTD_ADDR1_IDX].addr_val);
1454 | }
1455 |
1456 | new_key[DEINTD_ADDR2_IDX].type = CE_ADDRESS;
1457 | if (addr2 != NULL((void*)0)) {
1458 | copy_address_wmem(wmem_file_scope(), &new_key[DEINTD_ADDR2_IDX].addr_val, addr2);
1459 | }
1460 | else {
1461 | clear_address(&new_key[DEINTD_ADDR2_IDX].addr_val);
1462 | }
1463 |
1464 | new_key[DEINTD_PORT1_IDX].type = CE_PORT;
1465 | new_key[DEINTD_PORT1_IDX].port_val = port1;
1466 |
1467 | new_key[DEINTD_PORT2_IDX].type = CE_PORT;
1468 | new_key[DEINTD_PORT2_IDX].port_val = port2;
1469 |
1470 | new_key[DEINTD_ENDP_EXACT_IDX].type = CE_UINT;
1471 | new_key[DEINTD_ENDP_EXACT_IDX].uint_val = anchor;
1472 |
1473 | new_key[DEINTD_ENDP_EXACT_IDX + 1].type = CE_CONVERSATION_TYPE;
1474 | new_key[DEINTD_ENDP_EXACT_IDX + 1].conversation_type_val = ctype;
1475 |
1476 | // set the options and key pointer
1477 | conversation->options = options;
1478 | conversation->key_ptr = new_key;
1479 |
1480 | new_index++;
1481 |
1482 | conversation_insert_into_hashtable(conversation_hashtable_exact_addr_port_anc, conversation);
1483 |
1484 | return conversation;
1485 | }
1486 | }
1487 |
1488 | /*
1489 | * Set the port 2 value in a key. Remove the original from table,
1490 | * update the options and port values, insert the updated key.
1491 | */
1492 | void
1493 | conversation_set_port2(conversation_t *conv, const uint32_t port)
1494 | {
1495 | DISSECTOR_ASSERT_HINT(!(conv->options & CONVERSATION_TEMPLATE),((void) ((!(conv->options & 0x08)) ? (void)0 : (proto_report_dissector_bug ("%s:%u: failed assertion \"%s\" (%s)", "epan/conversation.c" , 1496, "!(conv->options & 0x08)", "Use the conversation_create_from_template function when the CONVERSATION_TEMPLATE bit is set in the options mask" ))))
1496 | "Use the conversation_create_from_template function when the CONVERSATION_TEMPLATE bit is set in the options mask")((void) ((!(conv->options & 0x08)) ? (void)0 : (proto_report_dissector_bug ("%s:%u: failed assertion \"%s\" (%s)", "epan/conversation.c" , 1496, "!(conv->options & 0x08)", "Use the conversation_create_from_template function when the CONVERSATION_TEMPLATE bit is set in the options mask" ))));
1497 |
1498 | DPRINT(("called for port=%d", port))(void)0;
1499 |
1500 | /*
1501 | * If the port 2 value is not wildcarded, don't set it.
1502 | */
1503 | if ((!(conv->options & NO_PORT20x02)) || (conv->options & NO_PORT2_FORCE0x04))
1504 | return;
1505 |
1506 | DINDENT()(void)0;
1507 | if (conv->options & NO_ADDR20x01) {
1508 | conversation_remove_from_hashtable(conversation_hashtable_no_addr2_or_port2, conv);
1509 | } else {
1510 | conversation_remove_from_hashtable(conversation_hashtable_no_port2, conv);
1511 | }
1512 |
1513 | // Shift our endpoint element over and set our port. We assume that conv->key_ptr
1514 | // was created with conversation_new and that we have enough element slots.
1515 | conv->options &= ~NO_PORT20x02;
1516 | if (conv->options & NO_ADDR20x01) {
1517 | // addr1,port1,endp -> addr1,port1,port2,endp
1518 | conv->key_ptr[ENDP_NO_ADDR2_IDX] = conv->key_ptr[ENDP_NO_ADDR2_PORT2_IDX];
1519 | conv->key_ptr[PORT2_NO_ADDR2_IDX].type = CE_PORT;
1520 | conv->key_ptr[PORT2_NO_ADDR2_IDX].port_val = port;
1521 | conversation_insert_into_hashtable(conversation_hashtable_no_addr2, conv);
1522 | } else {
1523 | // addr1,port1,addr2,endp -> addr1,port1,addr2,port2,endp
1524 | conv->key_ptr[ENDP_EXACT_IDX] = conv->key_ptr[ENDP_NO_PORT2_IDX];
1525 | conv->key_ptr[PORT2_IDX].type = CE_PORT;
1526 | conv->key_ptr[PORT2_IDX].port_val = port;
1527 | conversation_insert_into_hashtable(conversation_hashtable_exact_addr_port, conv);
1528 | }
1529 | DENDENT()(void)0;
1530 | }
1531 |
1532 | /*
1533 | * Set the address 2 value in a key. Remove the original from
1534 | * table, update the options and port values, insert the updated key.
1535 | */
1536 | void
1537 | conversation_set_addr2(conversation_t *conv, const address *addr)
1538 | {
1539 | char* addr_str;
1540 | DISSECTOR_ASSERT_HINT(!(conv->options & CONVERSATION_TEMPLATE),((void) ((!(conv->options & 0x08)) ? (void)0 : (proto_report_dissector_bug ("%s:%u: failed assertion \"%s\" (%s)", "epan/conversation.c" , 1541, "!(conv->options & 0x08)", "Use the conversation_create_from_template function when the CONVERSATION_TEMPLATE bit is set in the options mask" ))))
1541 | "Use the conversation_create_from_template function when the CONVERSATION_TEMPLATE bit is set in the options mask")((void) ((!(conv->options & 0x08)) ? (void)0 : (proto_report_dissector_bug ("%s:%u: failed assertion \"%s\" (%s)", "epan/conversation.c" , 1541, "!(conv->options & 0x08)", "Use the conversation_create_from_template function when the CONVERSATION_TEMPLATE bit is set in the options mask" ))));
1542 |
1543 | addr_str = address_to_str(NULL((void*)0), addr);
1544 | DPRINT(("called for addr=%s", addr_str))(void)0;
1545 | wmem_free(NULL((void*)0), addr_str);
1546 |
1547 | /*
1548 | * If the address 2 value is not wildcarded, don't set it.
1549 | */
1550 | if (!(conv->options & NO_ADDR20x01))
1551 | return;
1552 |
1553 | DINDENT()(void)0;
1554 | if (conv->options & NO_PORT20x02) {
1555 | conversation_remove_from_hashtable(conversation_hashtable_no_addr2_or_port2, conv);
1556 | } else {
1557 | conversation_remove_from_hashtable(conversation_hashtable_no_addr2, conv);
1558 | }
1559 |
1560 | // Shift our endpoint and, if needed, our port element over and set our address.
1561 | // We assume that conv->key_ptr was created with conversation_new and that we have
1562 | // enough element slots.
1563 | conv->options &= ~NO_ADDR20x01;
1564 | wmem_map_t *hashtable;
1565 | if (conv->options & NO_PORT20x02) {
1566 | // addr1,port1,endp -> addr1,port1,addr2,endp
1567 | conv->key_ptr[ENDP_NO_PORT2_IDX] = conv->key_ptr[ENDP_NO_ADDR2_PORT2_IDX];
1568 | hashtable = conversation_hashtable_no_port2;
1569 | } else {
1570 | // addr1,port1,port2,endp -> addr1,port1,addr2,port2,endp
1571 | conv->key_ptr[ENDP_EXACT_IDX] = conv->key_ptr[ENDP_NO_ADDR2_IDX];
1572 | conv->key_ptr[PORT2_IDX] = conv->key_ptr[PORT2_NO_ADDR2_IDX];
1573 | hashtable = conversation_hashtable_exact_addr_port;
1574 | }
1575 | conv->key_ptr[ADDR2_IDX].type = CE_ADDRESS;
1576 | copy_address_wmem(wmem_file_scope(), &conv->key_ptr[ADDR2_IDX].addr_val, addr);
1577 | conversation_insert_into_hashtable(hashtable, conv);
1578 | DENDENT()(void)0;
1579 | }
1580 |
1581 | static conversation_t *conversation_lookup_hashtable(wmem_map_t *conversation_hashtable, const uint32_t frame_num, conversation_element_t *conv_key)
1582 | {
1583 | conversation_t* convo = NULL((void*)0);
1584 | conversation_t* match = NULL((void*)0);
1585 | conversation_t* chain_head = NULL((void*)0);
1586 | chain_head = (conversation_t *)wmem_map_lookup(conversation_hashtable, conv_key);
1587 |
1588 | if (chain_head && (chain_head->setup_frame <= frame_num)) {
1589 | match = chain_head;
1590 |
1591 | if (chain_head->last && (chain_head->last->setup_frame <= frame_num))
1592 | return chain_head->last;
1593 |
1594 | if (chain_head->latest_found && (chain_head->latest_found->setup_frame <= frame_num))
1595 | match = chain_head->latest_found;
1596 |
1597 | for (convo = match; convo && convo->setup_frame <= frame_num; convo = convo->next) {
1598 | if (convo->setup_frame > match->setup_frame) {
1599 | match = convo;
1600 | }
1601 | }
1602 | }
1603 |
1604 | if (match) {
1605 | chain_head->latest_found = match;
1606 | }
1607 |
1608 | return match;
1609 | }
1610 |
1611 | conversation_t *find_conversation_full(const uint32_t frame_num, conversation_element_t *elements)
1612 | {
1613 | char *el_list_map_key = conversation_element_list_name(NULL((void*)0), elements);
1614 | wmem_map_t *el_list_map = (wmem_map_t *) wmem_map_lookup(conversation_hashtable_element_list, el_list_map_key);
1615 | g_free(el_list_map_key)(__builtin_object_size ((el_list_map_key), 0) != ((size_t) - 1 )) ? g_free_sized (el_list_map_key, __builtin_object_size ((el_list_map_key ), 0)) : (g_free) (el_list_map_key);
1616 | if (!el_list_map) {
1617 | return NULL((void*)0);
1618 | }
1619 |
1620 | return conversation_lookup_hashtable(el_list_map, frame_num, elements);
1621 | }
1622 |
1623 | /*
1624 | * Search a particular hash table for a conversation with the specified
1625 | * {addr1, port1, addr2, port2} and set up before frame_num.
1626 | */
1627 | static conversation_t *
1628 | conversation_lookup_exact(const uint32_t frame_num, const address *addr1, const uint32_t port1,
1629 | const address *addr2, const uint32_t port2, const conversation_type ctype)
1630 | {
1631 | conversation_element_t key[EXACT_IDX_COUNT] = {
1632 | { CE_ADDRESS, .addr_val = *addr1 },
1633 | { CE_PORT, .port_val = port1 },
1634 | { CE_ADDRESS, .addr_val = *addr2 },
1635 | { CE_PORT, .port_val = port2 },
1636 | { CE_CONVERSATION_TYPE, .conversation_type_val = ctype },
1637 | };
1638 | return conversation_lookup_hashtable(conversation_hashtable_exact_addr_port, frame_num, key);
1639 | }
1640 |
1641 | /*
1642 | * Search a particular hash table for a conversation with the specified
1643 | * {addr1, port1, port2} and set up before frame_num.
1644 | */
1645 | static conversation_t *
1646 | conversation_lookup_no_addr2(const uint32_t frame_num, const address *addr1, const uint32_t port1,
1647 | const uint32_t port2, const conversation_type ctype)
1648 | {
1649 | conversation_element_t key[NO_ADDR2_IDX_COUNT] = {
1650 | { CE_ADDRESS, .addr_val = *addr1 },
1651 | { CE_PORT, .port_val = port1 },
1652 | { CE_PORT, .port_val = port2 },
1653 | { CE_CONVERSATION_TYPE, .conversation_type_val = ctype },
1654 | };
1655 | return conversation_lookup_hashtable(conversation_hashtable_no_addr2, frame_num, key);
1656 | }
1657 |
1658 | /*
1659 | * Search a particular hash table for a conversation with the specified
1660 | * {addr1, port1, addr2} and set up before frame_num.
1661 | */
1662 | static conversation_t *
1663 | conversation_lookup_no_port2(const uint32_t frame_num, const address *addr1, const uint32_t port1,
1664 | const address *addr2, const conversation_type ctype)
1665 | {
1666 | conversation_element_t key[NO_PORT2_IDX_COUNT] = {
1667 | { CE_ADDRESS, .addr_val = *addr1 },
1668 | { CE_PORT, .port_val = port1 },
1669 | { CE_ADDRESS, .addr_val = *addr2 },
1670 | { CE_CONVERSATION_TYPE, .conversation_type_val = ctype },
1671 | };
1672 | return conversation_lookup_hashtable(conversation_hashtable_no_port2, frame_num, key);
1673 | }
1674 |
1675 | /*
1676 | * Search a particular hash table for a conversation with the specified
1677 | * {addr1, port1, addr2} and set up before frame_num.
1678 | */
1679 | static conversation_t *
1680 | conversation_lookup_no_addr2_or_port2(const uint32_t frame_num, const address *addr1, const uint32_t port1,
1681 | const conversation_type ctype)
1682 | {
1683 | conversation_element_t key[NO_ADDR2_PORT2_IDX_COUNT] = {
1684 | { CE_ADDRESS, .addr_val = *addr1 },
1685 | { CE_PORT, .port_val = port1 },
1686 | { CE_CONVERSATION_TYPE, .conversation_type_val = ctype },
1687 | };
1688 | return conversation_lookup_hashtable(conversation_hashtable_no_addr2_or_port2, frame_num, key);
1689 | }
1690 |
1691 | /*
1692 | * Search a particular hash table for a conversation with the specified
1693 | * {addr1, addr2} and set up before frame_num.
1694 | */
1695 | static conversation_t *
1696 | conversation_lookup_no_ports(const uint32_t frame_num, const address *addr1,
1697 | const address *addr2, const conversation_type ctype)
1698 | {
1699 | conversation_element_t key[ADDRS_IDX_COUNT] = {
1700 | { CE_ADDRESS, .addr_val = *addr1 },
1701 | { CE_ADDRESS, .addr_val = *addr2 },
1702 | { CE_CONVERSATION_TYPE, .conversation_type_val = ctype },
1703 | };
1704 | return conversation_lookup_hashtable(conversation_hashtable_exact_addr, frame_num, key);
1705 | }
1706 |
1707 | /*
1708 | * Search a particular hash table for a conversation with the specified
1709 | * {addr1, port1, addr2, port2, anchor} and set up before frame_num.
1710 | */
1711 | static conversation_t *
1712 | conversation_lookup_exact_anc(const uint32_t frame_num, const address *addr1, const uint32_t port1,
1713 | const address *addr2, const uint32_t port2, const conversation_type ctype,
1714 | const uint32_t anchor)
1715 | {
1716 | conversation_element_t key[DEINTD_EXACT_IDX_COUNT+1] = {
1717 | { CE_ADDRESS, .addr_val = *addr1 },
1718 | { CE_ADDRESS, .addr_val = *addr2 },
1719 | { CE_PORT, .port_val = port1 },
1720 | { CE_PORT, .port_val = port2 },
1721 | { CE_UINT, .uint_val = anchor },
1722 | { CE_CONVERSATION_TYPE, .conversation_type_val = ctype },
1723 | };
1724 | return conversation_lookup_hashtable(conversation_hashtable_exact_addr_port_anc, frame_num, key);
1725 | }
1726 |
1727 | /*
1728 | * Search a particular hash table for a conversation with the specified
1729 | * {addr1, addr2, anchor} and set up before frame_num.
1730 | */
1731 | static conversation_t *
1732 | conversation_lookup_no_ports_anc(const uint32_t frame_num, const address *addr1,
1733 | const address *addr2, const conversation_type ctype, const uint32_t anchor)
1734 | {
1735 | conversation_element_t key[DEINTD_ADDRS_IDX_COUNT+1] = {
1736 | { CE_ADDRESS, .addr_val = *addr1 },
1737 | { CE_ADDRESS, .addr_val = *addr2 },
1738 | { CE_UINT, .uint_val = anchor },
1739 | { CE_CONVERSATION_TYPE, .conversation_type_val = ctype },
1740 | };
1741 | return conversation_lookup_hashtable(conversation_hashtable_exact_addr_anc, frame_num, key);
1742 | }
1743 |
1744 | /*
1745 | * Search a particular hash table for a conversation with the specified
1746 | * {addr1, port1, port2, anchor} and set up before frame_num.
1747 | */
1748 | static conversation_t *
1749 | conversation_lookup_no_addr2_anc(const uint32_t frame_num, const address *addr1, const uint32_t port1,
1750 | const uint32_t port2, const conversation_type ctype,
1751 | const uint32_t anchor)
1752 | {
1753 | conversation_element_t key[DEINTD_NO_ADDR2_IDX_COUNT] = {
1754 | { CE_ADDRESS, .addr_val = *addr1 },
1755 | { CE_PORT, .port_val = port1 },
1756 | { CE_PORT, .port_val = port2 },
1757 | { CE_UINT, .uint_val = anchor },
1758 | { CE_CONVERSATION_TYPE, .conversation_type_val = ctype },
1759 | };
1760 | return conversation_lookup_hashtable(conversation_hashtable_no_addr2_anc , frame_num, key);
1761 | }
1762 |
1763 | /*
1764 | * Search a particular hash table for a conversation with the specified
1765 | * {addr1, port1, addr2, anchor} and set up before frame_num.
1766 | */
1767 | static conversation_t *
1768 | conversation_lookup_no_port2_anc(const uint32_t frame_num, const address *addr1, const uint32_t port1,
1769 | const address *addr2, const conversation_type ctype,
1770 | const uint32_t anchor)
1771 | {
1772 | conversation_element_t key[DEINTD_NO_PORT2_IDX_COUNT] = {
1773 | { CE_ADDRESS, .addr_val = *addr1 },
1774 | { CE_ADDRESS, .addr_val = *addr2 },
1775 | { CE_PORT, .port_val = port1 },
1776 | { CE_UINT, .uint_val = anchor },
1777 | { CE_CONVERSATION_TYPE, .conversation_type_val = ctype },
1778 | };
1779 | return conversation_lookup_hashtable(conversation_hashtable_exact_addr_port_anc, frame_num, key);
1780 | }
1781 |
1782 | /*
1783 | * Search a particular hash table for a conversation with the specified
1784 | * {addr1, port1, addr2} and set up before frame_num.
1785 | */
1786 | static conversation_t *
1787 | conversation_lookup_no_addr2_or_port2_anc(const uint32_t frame_num, const address *addr1, const uint32_t port1,
1788 | const conversation_type ctype, const uint32_t anchor)
1789 | {
1790 | conversation_element_t key[DEINTD_NO_ADDR2_PORT2_IDX_COUNT] = {
1791 | { CE_ADDRESS, .addr_val = *addr1 },
1792 | { CE_PORT, .port_val = port1 },
1793 | { CE_UINT, .uint_val = anchor },
1794 | { CE_CONVERSATION_TYPE, .conversation_type_val = ctype },
1795 | };
1796 | return conversation_lookup_hashtable(conversation_hashtable_no_addr2_or_port2_anc, frame_num, key);
1797 | }
1798 |
1799 | /*
1800 | * Search a particular hash table for a conversation with the specified
1801 | * {addr1, addr2, key1, key2, key3} and set up before frame_num.
1802 | * At this moment only the deinterlace table is likely to be called.
1803 | */
1804 | static conversation_t *
1805 | conversation_lookup_deinterlacer(const uint32_t frame_num, const address *addr1,
1806 | const address *addr2, const conversation_type ctype,
1807 | const uint32_t key1, const uint32_t key2, const uint32_t key3)
1808 | {
1809 | conversation_element_t key[DEINTR_ENDP_IDX+1] = {
1810 | { CE_ADDRESS, .addr_val = *addr1 },
1811 | { CE_ADDRESS, .addr_val = *addr2 },
1812 | { CE_UINT, .uint_val = key1 },
1813 | { CE_UINT, .uint_val = key2 },
1814 | { CE_UINT, .uint_val = key3 },
1815 | { CE_CONVERSATION_TYPE, .conversation_type_val = ctype },
1816 | };
1817 | return conversation_lookup_hashtable(conversation_hashtable_deinterlacer, frame_num, key);
1818 | }
1819 |
1820 | /*
1821 | * Given two address/port pairs for a packet, search for a conversation
1822 | * containing packets between those address/port pairs. Returns NULL if
1823 | * not found.
1824 | *
1825 | * We try to find the most exact match that we can, and then proceed to
1826 | * try wildcard matches on the "addr_b" and/or "port_b" argument if a more
1827 | * exact match failed.
1828 | *
1829 | * Either or both of the "addr_b" and "port_b" arguments may be specified as
1830 | * a wildcard by setting the NO_ADDR_B or NO_PORT_B flags in the "options"
1831 | * argument. We do only wildcard matches on addresses and ports specified
1832 | * as wildcards.
1833 | *
1834 | * I.e.:
1835 | *
1836 | * if neither "addr_b" nor "port_b" were specified as wildcards, we
1837 | * do an exact match (addr_a/port_a and addr_b/port_b) and, if that
1838 | * succeeds, we return a pointer to the matched conversation;
1839 | *
1840 | * otherwise, if "port_b" wasn't specified as a wildcard, we try to
1841 | * match any address 2 with the specified port 2 (addr_a/port_a and
1842 | * {any}/port_b) and, if that succeeds, we return a pointer to the
1843 | * matched conversation;
1844 | *
1845 | * otherwise, if "addr_b" wasn't specified as a wildcard, we try to
1846 | * match any port 2 with the specified address 2 (addr_a/port_a and
1847 | * addr_b/{any}) and, if that succeeds, we return a pointer to the
1848 | * matched conversation;
1849 | *
1850 | * otherwise, we try to match any address 2 and any port 2
1851 | * (addr_a/port_a and {any}/{any}) and, if that succeeds, we return
1852 | * a pointer to the matched conversation;
1853 | *
1854 | * otherwise, we found no matching conversation, and return NULL.
1855 | */
1856 | conversation_t *
1857 | find_conversation(const uint32_t frame_num, const address *addr_a, const address *addr_b, const conversation_type ctype,
1858 | const uint32_t port_a, const uint32_t port_b, const unsigned options)
1859 | {
1860 | conversation_t *conversation, *other_conv;
1861 |
1862 | if (!addr_a) {
1863 | addr_a = &null_address_;
1864 | }
1865 |
1866 | if (!addr_b) {
1867 | addr_b = &null_address_;
1868 | }
1869 |
1870 | DINSTR(char *addr_a_str = address_to_str(NULL, addr_a))(void)0;
1871 | DINSTR(char *addr_b_str = address_to_str(NULL, addr_b))(void)0;
1872 | /*
1873 | * Verify that the correct options are used, if any.
1874 | */
1875 | DISSECTOR_ASSERT_HINT((options == 0) || (options & NO_MASK_B), "Use NO_ADDR_B and/or NO_PORT_B as option")((void) (((options == 0) || (options & 0xFFFF0000)) ? (void )0 : (proto_report_dissector_bug("%s:%u: failed assertion \"%s\" (%s)" , "epan/conversation.c", 1875, "(options == 0) || (options & 0xFFFF0000)" , "Use NO_ADDR_B and/or NO_PORT_B as option"))));
1876 | /*
1877 | * First try an exact match, if we have two addresses and ports.
1878 | */
1879 | if (!(options & (NO_ADDR_B0x00010000|NO_PORT_B0x00020000|NO_PORT_X0x00040000|EXACT_EXCLUDED0x00200000))) {
1880 | /*
1881 | * Neither search address B nor search port B are wildcarded,
1882 | * start out with an exact match.
1883 | */
1884 | DPRINT(("trying exact match: %s:%d -> %s:%d",(void)0
1885 | addr_a_str, port_a, addr_b_str, port_b))(void)0;
1886 | conversation = conversation_lookup_exact(frame_num, addr_a, port_a, addr_b, port_b, ctype);
1887 | /*
1888 | * Look for an alternate conversation in the opposite direction, which
1889 | * might fit better. Note that using the helper functions such as
1890 | * find_conversation_pinfo and find_or_create_conversation will finally
1891 | * call this function and look for an orientation-agnostic conversation.
1892 | * If oriented conversations had to be implemented, amend this code or
1893 | * create new functions.
1894 | */
1895 |
1896 | DPRINT(("trying exact match: %s:%d -> %s:%d",(void)0
1897 | addr_b_str, port_b, addr_a_str, port_a))(void)0;
1898 | other_conv = conversation_lookup_exact(frame_num, addr_b, port_b, addr_a, port_a, ctype);
1899 | if (other_conv != NULL((void*)0)) {
1900 | if (conversation != NULL((void*)0)) {
1901 | if(other_conv->conv_index > conversation->conv_index) {
1902 | conversation = other_conv;
1903 | }
1904 | }
1905 | else {
1906 | conversation = other_conv;
1907 | }
1908 | }
1909 | if ((conversation == NULL((void*)0)) && (addr_a->type == AT_FC)) {
1910 | /* In Fibre channel, OXID & RXID are never swapped as
1911 | * TCP/UDP ports are in TCP/IP.
1912 | */
1913 | DPRINT(("trying exact match: %s:%d -> %s:%d",(void)0
1914 | addr_b_str, port_a, addr_a_str, port_b))(void)0;
1915 | conversation = conversation_lookup_exact(frame_num, addr_b, port_a, addr_a, port_b, ctype);
1916 | }
1917 | DPRINT(("exact match %sfound",conversation?"":"not "))(void)0;
1918 | if (conversation != NULL((void*)0))
1919 | goto end;
1920 | else if(options & NO_GREEDY0x00100000)
1921 | goto end;
1922 | }
1923 |
1924 | /*
1925 | * Well, that didn't find anything. Try matches that wildcard
1926 | * one of the addresses, if we have two ports.
1927 | */
1928 | if (!(options & (NO_PORT_B0x00020000|NO_PORT_X0x00040000))) {
1929 | /*
1930 | * Search port B isn't wildcarded.
1931 | *
1932 | * First try looking for a conversation with the specified
1933 | * address A and port A as the first address and port, and
1934 | * with any address and the specified port B as the second
1935 | * address and port.
1936 | * ("addr_b" doesn't take part in this lookup.)
1937 | */
1938 | DPRINT(("trying wildcarded match: %s:%d -> *:%d",(void)0
1939 | addr_a_str, port_a, port_b))(void)0;
1940 | conversation = conversation_lookup_no_addr2(frame_num, addr_a, port_a, port_b, ctype);
1941 | if ((conversation == NULL((void*)0)) && (addr_a->type == AT_FC)) {
1942 | /* In Fibre channel, OXID & RXID are never swapped as
1943 | * TCP/UDP ports are in TCP/IP.
1944 | */
1945 | DPRINT(("trying wildcarded match: %s:%d -> *:%d",(void)0
1946 | addr_b_str, port_a, port_b))(void)0;
1947 | conversation = conversation_lookup_no_addr2(frame_num, addr_b, port_a, port_b, ctype);
1948 | }
1949 | if (conversation != NULL((void*)0)) {
1950 | /*
1951 | * If search address B isn't wildcarded, and this is for a
1952 | * connection-oriented protocol, set the second address for this
1953 | * conversation to address B, as that's the address that matched the
1954 | * wildcarded second address for this conversation.
1955 | *
1956 | * (This assumes that, for all connection oriented protocols, the
1957 | * endpoints of a connection have only one address each, i.e. you
1958 | * don't get packets in a given direction coming from more than one
1959 | * address, unless the CONVERSATION_TEMPLATE option is set.)
1960 | */
1961 | DPRINT(("wildcarded dest address match found"))(void)0;
1962 | if (!(conversation->options & NO_ADDR20x01) && ctype != CONVERSATION_UDP)
1963 | {
1964 | if (!(conversation->options & CONVERSATION_TEMPLATE0x08))
1965 | {
1966 | conversation_set_addr2(conversation, addr_b);
1967 | }
1968 | else
1969 | {
1970 | conversation =
1971 | conversation_create_from_template(conversation, addr_b, 0);
1972 | }
1973 | }
1974 | goto end;
1975 | }
1976 |
1977 | /*
1978 | * Well, that didn't find anything.
1979 | * If search address B was specified, try looking for a
1980 | * conversation with the specified address B and port B as
1981 | * the first address and port, and with any address and the
1982 | * specified port A as the second address and port (this
1983 | * packet may be going in the opposite direction from the
1984 | * first packet in the conversation).
1985 | * ("addr_a" doesn't take part in this lookup.)
1986 | */
1987 | if (!(options & NO_ADDR_B0x00010000)) {
1988 | DPRINT(("trying wildcarded match: %s:%d -> *:%d",(void)0
1989 | addr_b_str, port_b, port_a))(void)0;
1990 | conversation = conversation_lookup_no_addr2(frame_num, addr_b, port_b, port_a, ctype);
1991 | if (conversation != NULL((void*)0)) {
1992 | /*
1993 | * If this is for a connection-oriented
1994 | * protocol, set the second address for
1995 | * this conversation to address A, as
1996 | * that's the address that matched the
1997 | * wildcarded second address for this
1998 | * conversation.
1999 | */
2000 | DPRINT(("match found"))(void)0;
2001 | if (ctype != CONVERSATION_UDP) {
2002 | if (!(conversation->options & CONVERSATION_TEMPLATE0x08))
2003 | {
2004 | conversation_set_addr2(conversation, addr_a);
2005 | }
2006 | else
2007 | {
2008 | conversation =
2009 | conversation_create_from_template(conversation, addr_a, 0);
2010 | }
2011 | }
2012 | goto end;
2013 | }
2014 | }
2015 | }
2016 |
2017 | /*
2018 | * Well, that didn't find anything. Try matches that wildcard
2019 | * one of the ports, if we have two addresses.
2020 | */
2021 | if (!(options & (NO_ADDR_B0x00010000|NO_PORT_X0x00040000))) {
2022 | /*
2023 | * Search address B isn't wildcarded.
2024 | *
2025 | * First try looking for a conversation with the specified
2026 | * address A and port A as the first address and port, and
2027 | * with the specified address B and any port as the second
2028 | * address and port.
2029 | * ("port_b" doesn't take part in this lookup.)
2030 | */
2031 | DPRINT(("trying wildcarded match: %s:%d -> %s:*",(void)0
2032 | addr_a_str, port_a, addr_b_str))(void)0;
2033 | conversation = conversation_lookup_no_port2(frame_num, addr_a, port_a, addr_b, ctype);
2034 | if ((conversation == NULL((void*)0)) && (addr_a->type == AT_FC)) {
2035 | /* In Fibre channel, OXID & RXID are never swapped as
2036 | * TCP/UDP ports are in TCP/IP
2037 | */
2038 | DPRINT(("trying wildcarded match: %s:%d -> %s:*", addr_b_str, port_a, addr_a_str))(void)0;
2039 | conversation = conversation_lookup_no_port2(frame_num, addr_b, port_a, addr_a, ctype);
2040 | }
2041 | if (conversation != NULL((void*)0)) {
2042 | /*
2043 | * If search port B isn't wildcarded, and this is for a connection-
2044 | * oriented protocol, set the second port for this conversation to
2045 | * port B, as that's the port that matched the wildcarded second port
2046 | * for this conversation.
2047 | *
2048 | * (This assumes that, for all connection oriented protocols, the
2049 | * endpoints of a connection have only one port each, i.e. you don't
2050 | * get packets in a given direction coming from more than one port,
2051 | * unless the CONVERSATION_TEMPLATE option is set.)
2052 | */
2053 | DPRINT(("match found"))(void)0;
2054 | if (!(conversation->options & NO_PORT20x02) && ctype != CONVERSATION_UDP)
2055 | {
2056 | if (!(conversation->options & CONVERSATION_TEMPLATE0x08))
2057 | {
2058 | conversation_set_port2(conversation, port_b);
2059 | }
2060 | else
2061 | {
2062 | conversation =
2063 | conversation_create_from_template(conversation, 0, port_b);
2064 | }
2065 | }
2066 | goto end;
2067 | }
2068 |
2069 | /*
2070 | * Well, that didn't find anything.
2071 | * If search port B was specified, try looking for a
2072 | * conversation with the specified address B and port B
2073 | * as the first address and port, and with the specified
2074 | * address A and any port as the second address and port
2075 | * (this packet may be going in the opposite direction
2076 | * from the first packet in the conversation).
2077 | * ("port_a" doesn't take part in this lookup.)
2078 | */
2079 | if (!(options & NO_PORT_B0x00020000)) {
2080 | DPRINT(("trying wildcarded match: %s:%d -> %s:*",(void)0
2081 | addr_b_str, port_b, addr_a_str))(void)0;
2082 | conversation = conversation_lookup_no_port2(frame_num, addr_b, port_b, addr_a, ctype);
2083 | if (conversation != NULL((void*)0)) {
2084 | /*
2085 | * If this is for a connection-oriented
2086 | * protocol, set the second port for
2087 | * this conversation to port A, as
2088 | * that's the address that matched the
2089 | * wildcarded second address for this
2090 | * conversation.
2091 | */
2092 | DPRINT(("match found"))(void)0;
2093 | if (ctype != CONVERSATION_UDP)
2094 | {
2095 | if (!(conversation->options & CONVERSATION_TEMPLATE0x08))
2096 | {
2097 | conversation_set_port2(conversation, port_a);
2098 | }
2099 | else
2100 | {
2101 | conversation =
2102 | conversation_create_from_template(conversation, 0, port_a);
2103 | }
2104 | }
2105 | goto end;
2106 | }
2107 | }
2108 | if(options & NO_GREEDY0x00100000) {
2109 | goto end;
2110 | }
2111 | }
2112 |
2113 | /*
2114 | * Well, that didn't find anything. Try matches that wildcard
2115 | * one address/port pair.
2116 | *
2117 | * First try looking for a conversation with the specified address A
2118 | * and port A as the first address and port.
2119 | * (Neither "addr_b" nor "port_b" take part in this lookup.)
2120 | */
2121 | if (!(options & NO_PORT_X0x00040000)) {
2122 | DPRINT(("trying wildcarded match: %s:%d -> *:*", addr_a_str, port_a))(void)0;
2123 | conversation = conversation_lookup_no_addr2_or_port2(frame_num, addr_a, port_a, ctype);
2124 | if (conversation != NULL((void*)0)) {
2125 | /*
2126 | * If this is for a connection-oriented protocol:
2127 | *
2128 | * if search address B isn't wildcarded, set the
2129 | * second address for this conversation to address
2130 | * B, as that's the address that matched the
2131 | * wildcarded second address for this conversation;
2132 | *
2133 | * if search port B isn't wildcarded, set the
2134 | * second port for this conversation to port B,
2135 | * as that's the port that matched the wildcarded
2136 | * second port for this conversation.
2137 | */
2138 | DPRINT(("match found"))(void)0;
2139 | if (ctype != CONVERSATION_UDP)
2140 | {
2141 | if (!(conversation->options & CONVERSATION_TEMPLATE0x08))
2142 | {
2143 | if (!(conversation->options & NO_ADDR20x01))
2144 | conversation_set_addr2(conversation, addr_b);
2145 | if (!(conversation->options & NO_PORT20x02))
2146 | conversation_set_port2(conversation, port_b);
2147 | }
2148 | else
2149 | {
2150 | conversation =
2151 | conversation_create_from_template(conversation, addr_b, port_b);
2152 | }
2153 | }
2154 | goto end;
2155 | }
2156 | /* for Infiniband, don't try to look in addresses of reverse
2157 | * direction, because it could be another different
2158 | * valid conversation than what is being searched using
2159 | * addr_a, port_a.
2160 | */
2161 | if (ctype != CONVERSATION_IBQP)
2162 | {
2163 |
2164 | /*
2165 | * Well, that didn't find anything.
2166 | * If search address and port B were specified, try looking for a
2167 | * conversation with the specified address B and port B as the
2168 | * first address and port, and with any second address and port
2169 | * (this packet may be going in the opposite direction from the
2170 | * first packet in the conversation).
2171 | * (Neither "addr_a" nor "port_a" take part in this lookup.)
2172 | */
2173 | if (addr_a->type == AT_FC) {
2174 | DPRINT(("trying wildcarded match: %s:%d -> *:*",(void)0
2175 | addr_b_str, port_a))(void)0;
2176 | conversation = conversation_lookup_no_addr2_or_port2(frame_num, addr_b, port_a, ctype);
2177 | } else {
2178 | DPRINT(("trying wildcarded match: %s:%d -> *:*",(void)0
2179 | addr_b_str, port_b))(void)0;
2180 | conversation = conversation_lookup_no_addr2_or_port2(frame_num, addr_b, port_b, ctype);
2181 | }
2182 | if (conversation != NULL((void*)0)) {
2183 | /*
2184 | * If this is for a connection-oriented protocol, set the
2185 | * second address for this conversation to address A, as
2186 | * that's the address that matched the wildcarded second
2187 | * address for this conversation, and set the second port
2188 | * for this conversation to port A, as that's the port
2189 | * that matched the wildcarded second port for this
2190 | * conversation.
2191 | */
2192 | DPRINT(("match found"))(void)0;
2193 | if (ctype != CONVERSATION_UDP)
2194 | {
2195 | if (!(conversation->options & CONVERSATION_TEMPLATE0x08))
2196 | {
2197 | conversation_set_addr2(conversation, addr_a);
2198 | conversation_set_port2(conversation, port_a);
2199 | }
2200 | else
2201 | {
2202 | conversation = conversation_create_from_template(conversation, addr_a, port_a);
2203 | }
2204 | }
2205 | goto end;
2206 | }
2207 | }
2208 | }
2209 |
2210 | /*
2211 | * Well, that didn't find anything. Try matches between two
2212 | * addresses, but no ports. Typically ETH and IP protocols fall
2213 | * into this category.
2214 | *
2215 | * First try looking for a conversation with the specified address A
2216 | * and address B.
2217 | * (Neither "port_a" nor "port_b" take part in this lookup.)
2218 | */
2219 | if (options & NO_PORT_X0x00040000) {
2220 | /*
2221 | * Search for conversations between two addresses, strictly
2222 | */
2223 | DPRINT(("trying exact match: %s -> %s",(void)0
2224 | addr_a_str, addr_b_str))(void)0;
2225 | conversation = conversation_lookup_no_ports(frame_num, addr_a, addr_b, ctype);
2226 |
2227 | if (conversation != NULL((void*)0)) {
2228 | DPRINT(("match found"))(void)0;
2229 | goto end;
2230 | }
2231 | /*
2232 | * Look for a conversation in the opposite direction.
2233 | */
2234 | else {
2235 | DPRINT(("trying exact match: %s -> %s",(void)0
2236 | addr_b_str, addr_a_str))(void)0;
2237 | conversation = conversation_lookup_no_ports(frame_num, addr_b, addr_a, ctype);
2238 | if (conversation != NULL((void*)0)) {
2239 | DPRINT(("match found"))(void)0;
2240 | goto end;
2241 | }
2242 | }
2243 | }
2244 |
2245 | DPRINT(("no matches found"))(void)0;
2246 |
2247 | /*
2248 | * We found no conversation.
2249 | */
2250 | conversation = NULL((void*)0);
2251 |
2252 | end:
2253 | DINSTR(wmem_free(NULL, addr_a_str))(void)0;
2254 | DINSTR(wmem_free(NULL, addr_b_str))(void)0;
2255 | return conversation;
2256 | }
2257 |
2258 | conversation_t *
2259 | find_conversation_deinterlaced(const uint32_t frame_num, const address *addr_a, const address *addr_b, const conversation_type ctype,
2260 | const uint32_t port_a, const uint32_t port_b, const uint32_t anchor, const unsigned options)
2261 | {
2262 | conversation_t *conversation, *other_conv;
2263 |
2264 | if (!addr_a) {
2265 | addr_a = &null_address_;
2266 | }
2267 |
2268 | if (!addr_b) {
2269 | addr_b = &null_address_;
2270 | }
2271 |
2272 | DINSTR(char *addr_a_str = address_to_str(NULL, addr_a))(void)0;
2273 | DINSTR(char *addr_b_str = address_to_str(NULL, addr_b))(void)0;
2274 |
2275 | /*
2276 | * First try an exact match, if we have two addresses and ports.
2277 | */
2278 | if (!(options & (NO_ADDR_B0x00010000|NO_PORT_B0x00020000|NO_PORTS0x010|EXACT_EXCLUDED0x00200000) )) {
2279 | /*
2280 | * Neither search address B nor search port B are wildcarded,
2281 | * start out with an exact match.
2282 | */
2283 | DPRINT(("trying exact match: %s:%d -> %s:%d",(void)0
2284 | addr_a_str, port_a, addr_b_str, port_b))(void)0;
2285 | conversation = conversation_lookup_exact_anc(frame_num, addr_a, port_a, addr_b, port_b, ctype, anchor);
2286 | /*
2287 | * Look for an alternate conversation in the opposite direction, which
2288 | * might fit better. Note that using the helper functions such as
2289 | * find_conversation_pinfo and find_or_create_conversation will finally
2290 | * call this function and look for an orientation-agnostic conversation.
2291 | * If oriented conversations had to be implemented, amend this code or
2292 | * create new functions.
2293 | */
2294 |
2295 | DPRINT(("trying exact match: %s:%d -> %s:%d",(void)0
2296 | addr_b_str, port_b, addr_a_str, port_a))(void)0;
2297 | other_conv = conversation_lookup_exact_anc(frame_num, addr_b, port_b, addr_a, port_a, ctype, anchor);
2298 | if (other_conv != NULL((void*)0)) {
2299 | if (conversation != NULL((void*)0)) {
2300 | if(other_conv->conv_index > conversation->conv_index) {
2301 | conversation = other_conv;
2302 | }
2303 | }
2304 | else {
2305 | conversation = other_conv;
2306 | }
2307 | }
2308 | if ((conversation == NULL((void*)0)) && (addr_a->type == AT_FC)) {
2309 | /* In Fibre channel, OXID & RXID are never swapped as
2310 | * TCP/UDP ports are in TCP/IP.
2311 | */
2312 | DPRINT(("trying exact match: %s:%d -> %s:%d",(void)0
2313 | addr_b_str, port_a, addr_a_str, port_b))(void)0;
2314 | conversation = conversation_lookup_exact_anc(frame_num, addr_b, port_a, addr_a, port_b, ctype, anchor);
2315 | }
2316 | DPRINT(("exact match %sfound",conversation?"":"not "))(void)0;
2317 | if (conversation != NULL((void*)0)) {
2318 | goto end;
2319 | }
2320 | else if(options & NO_GREEDY0x00100000) {
2321 | goto end;
2322 | }
2323 | }
2324 |
2325 | /*
2326 | * Well, that didn't find anything. Try matches that wildcard
2327 | * one of the addresses, if we have two ports.
2328 | */
2329 | if (!(options & (NO_PORT_B0x00020000|NO_PORTS0x010))) {
2330 | /*
2331 | * Search port B isn't wildcarded.
2332 | *
2333 | * First try looking for a conversation with the specified
2334 | * address A and port A as the first address and port, and
2335 | * with any address and the specified port B as the second
2336 | * address and port.
2337 | * ("addr_b" doesn't take part in this lookup.)
2338 | */
2339 | DPRINT(("trying wildcarded match: %s:%d -> *:%d",(void)0
2340 | addr_a_str, port_a, port_b))(void)0;
2341 | conversation = conversation_lookup_no_addr2_anc(frame_num, addr_a, port_a, port_b, ctype, anchor);
2342 | if ((conversation == NULL((void*)0)) && (addr_a->type == AT_FC)) {
2343 | /* In Fibre channel, OXID & RXID are never swapped as
2344 | * TCP/UDP ports are in TCP/IP.
2345 | */
2346 | DPRINT(("trying wildcarded match: %s:%d -> *:%d",(void)0
2347 | addr_b_str, port_a, port_b))(void)0;
2348 | conversation = conversation_lookup_no_addr2_anc(frame_num, addr_b, port_a, port_b, ctype, anchor);
2349 | }
2350 | if (conversation != NULL((void*)0)) {
2351 | /*
2352 | * If search address B isn't wildcarded, and this is for a
2353 | * connection-oriented protocol, set the second address for this
2354 | * conversation to address B, as that's the address that matched the
2355 | * wildcarded second address for this conversation.
2356 | *
2357 | * (This assumes that, for all connection oriented protocols, the
2358 | * endpoints of a connection have only one address each, i.e. you
2359 | * don't get packets in a given direction coming from more than one
2360 | * address, unless the CONVERSATION_TEMPLATE option is set.)
2361 | */
2362 | DPRINT(("wildcarded dest address match found"))(void)0;
2363 | if (!(conversation->options & NO_ADDR20x01) && ctype != CONVERSATION_UDP)
2364 | {
2365 | if (!(conversation->options & CONVERSATION_TEMPLATE0x08))
2366 | {
2367 | conversation_set_addr2(conversation, addr_b);
2368 | }
2369 | else
2370 | {
2371 | conversation =
2372 | conversation_create_from_template(conversation, addr_b, 0);
2373 | }
2374 | }
2375 | goto end;
2376 | }
2377 |
2378 | /*
2379 | * Well, that didn't find anything.
2380 | * If search address B was specified, try looking for a
2381 | * conversation with the specified address B and port B as
2382 | * the first address and port, and with any address and the
2383 | * specified port A as the second address and port (this
2384 | * packet may be going in the opposite direction from the
2385 | * first packet in the conversation).
2386 | * ("addr_a" doesn't take part in this lookup.)
2387 | */
2388 | if (!(options & NO_ADDR_B0x00010000)) {
2389 | DPRINT(("trying wildcarded match: %s:%d -> *:%d",(void)0
2390 | addr_b_str, port_b, port_a))(void)0;
2391 | conversation = conversation_lookup_no_addr2_anc(frame_num, addr_b, port_b, port_a, ctype, anchor);
2392 | if (conversation != NULL((void*)0)) {
2393 | /*
2394 | * If this is for a connection-oriented
2395 | * protocol, set the second address for
2396 | * this conversation to address A, as
2397 | * that's the address that matched the
2398 | * wildcarded second address for this
2399 | * conversation.
2400 | */
2401 | DPRINT(("match found"))(void)0;
2402 | if (ctype != CONVERSATION_UDP) {
2403 | if (!(conversation->options & CONVERSATION_TEMPLATE0x08))
2404 | {
2405 | conversation_set_addr2(conversation, addr_a);
2406 | }
2407 | else
2408 | {
2409 | conversation =
2410 | conversation_create_from_template(conversation, addr_a, 0);
2411 | }
2412 | }
2413 | goto end;
2414 | }
2415 | }
2416 | }
2417 |
2418 | /*
2419 | * Well, that didn't find anything. Try matches that wildcard
2420 | * one of the ports, if we have two addresses.
2421 | */
2422 | if (!(options & (NO_ADDR_B0x00010000|NO_PORTS0x010))) {
2423 | /*
2424 | * Search address B isn't wildcarded.
2425 | *
2426 | * First try looking for a conversation with the specified
2427 | * address A and port A as the first address and port, and
2428 | * with the specified address B and any port as the second
2429 | * address and port.
2430 | * ("port_b" doesn't take part in this lookup.)
2431 | */
2432 | DPRINT(("trying wildcarded match: %s:%d -> %s:*",(void)0
2433 | addr_a_str, port_a, addr_b_str))(void)0;
2434 | conversation = conversation_lookup_no_port2_anc(frame_num, addr_a, port_a, addr_b, ctype, anchor);
2435 | if ((conversation == NULL((void*)0)) && (addr_a->type == AT_FC)) {
2436 | /* In Fibre channel, OXID & RXID are never swapped as
2437 | * TCP/UDP ports are in TCP/IP
2438 | */
2439 | DPRINT(("trying wildcarded match: %s:%d -> %s:*", addr_b_str, port_a, addr_a_str))(void)0;
2440 | conversation = conversation_lookup_no_port2_anc(frame_num, addr_b, port_a, addr_a, ctype, anchor);
2441 | }
2442 | if (conversation != NULL((void*)0)) {
2443 | /*
2444 | * If search port B isn't wildcarded, and this is for a connection-
2445 | * oriented protocol, set the second port for this conversation to
2446 | * port B, as that's the port that matched the wildcarded second port
2447 | * for this conversation.
2448 | *
2449 | * (This assumes that, for all connection oriented protocols, the
2450 | * endpoints of a connection have only one port each, i.e. you don't
2451 | * get packets in a given direction coming from more than one port,
2452 | * unless the CONVERSATION_TEMPLATE option is set.)
2453 | */
2454 | DPRINT(("match found"))(void)0;
2455 | if (!(conversation->options & NO_PORT20x02) && ctype != CONVERSATION_UDP)
2456 | {
2457 | if (!(conversation->options & CONVERSATION_TEMPLATE0x08))
2458 | {
2459 | conversation_set_port2(conversation, port_b);
2460 | }
2461 | else
2462 | {
2463 | conversation =
2464 | conversation_create_from_template(conversation, 0, port_b);
2465 | }
2466 | }
2467 | goto end;
2468 | }
2469 |
2470 | /*
2471 | * Well, that didn't find anything.
2472 | * If search port B was specified, try looking for a
2473 | * conversation with the specified address B and port B
2474 | * as the first address and port, and with the specified
2475 | * address A and any port as the second address and port
2476 | * (this packet may be going in the opposite direction
2477 | * from the first packet in the conversation).
2478 | * ("port_a" doesn't take part in this lookup.)
2479 | */
2480 | if (!(options & NO_PORT_B0x00020000)) {
2481 | DPRINT(("trying wildcarded match: %s:%d -> %s:*",(void)0
2482 | addr_b_str, port_b, addr_a_str))(void)0;
2483 | conversation = conversation_lookup_no_port2_anc(frame_num, addr_b, port_b, addr_a, ctype, anchor);
2484 | if (conversation != NULL((void*)0)) {
2485 | /*
2486 | * If this is for a connection-oriented
2487 | * protocol, set the second port for
2488 | * this conversation to port A, as
2489 | * that's the address that matched the
2490 | * wildcarded second address for this
2491 | * conversation.
2492 | */
2493 | DPRINT(("match found"))(void)0;
2494 | if (ctype != CONVERSATION_UDP)
2495 | {
2496 | if (!(conversation->options & CONVERSATION_TEMPLATE0x08))
2497 | {
2498 | conversation_set_port2(conversation, port_a);
2499 | }
2500 | else
2501 | {
2502 | conversation =
2503 | conversation_create_from_template(conversation, 0, port_a);
2504 | }
2505 | }
2506 | goto end;
2507 | }
2508 | }
2509 | if(options & NO_GREEDY0x00100000) {
2510 | goto end;
2511 | }
2512 | }
2513 |
2514 | /*
2515 | * Well, that didn't find anything. Try matches that wildcard
2516 | * one address/port pair.
2517 | *
2518 | * First try looking for a conversation with the specified address A
2519 | * and port A as the first address and port.
2520 | * (Neither "addr_b" nor "port_b" take part in this lookup.)
2521 | */
2522 | DPRINT(("trying wildcarded match: %s:%d -> *:*", addr_a_str, port_a))(void)0;
2523 | conversation = conversation_lookup_no_addr2_or_port2_anc(frame_num, addr_a, port_a, ctype, anchor);
2524 | if (conversation != NULL((void*)0)) {
2525 | /*
2526 | * If this is for a connection-oriented protocol:
2527 | *
2528 | * if search address B isn't wildcarded, set the
2529 | * second address for this conversation to address
2530 | * B, as that's the address that matched the
2531 | * wildcarded second address for this conversation;
2532 | *
2533 | * if search port B isn't wildcarded, set the
2534 | * second port for this conversation to port B,
2535 | * as that's the port that matched the wildcarded
2536 | * second port for this conversation.
2537 | */
2538 | DPRINT(("match found"))(void)0;
2539 | if (ctype != CONVERSATION_UDP)
2540 | {
2541 | if (!(conversation->options & CONVERSATION_TEMPLATE0x08))
2542 | {
2543 | if (!(conversation->options & NO_ADDR20x01))
2544 | conversation_set_addr2(conversation, addr_b);
2545 | if (!(conversation->options & NO_PORT20x02))
2546 | conversation_set_port2(conversation, port_b);
2547 | }
2548 | else
2549 | {
2550 | conversation =
2551 | conversation_create_from_template(conversation, addr_b, port_b);
2552 | }
2553 | }
2554 | goto end;
2555 | }
2556 |
2557 | /* for Infiniband, don't try to look in addresses of reverse
2558 | * direction, because it could be another different
2559 | * valid conversation than what is being searched using
2560 | * addr_a, port_a.
2561 | */
2562 | if (ctype != CONVERSATION_IBQP)
2563 | {
2564 |
2565 | /*
2566 | * Well, that didn't find anything.
2567 | * If search address and port B were specified, try looking for a
2568 | * conversation with the specified address B and port B as the
2569 | * first address and port, and with any second address and port
2570 | * (this packet may be going in the opposite direction from the
2571 | * first packet in the conversation).
2572 | * (Neither "addr_a" nor "port_a" take part in this lookup.)
2573 | */
2574 | if (addr_a->type == AT_FC) {
2575 | DPRINT(("trying wildcarded match: %s:%d -> *:*",(void)0
2576 | addr_b_str, port_a))(void)0;
2577 | conversation = conversation_lookup_no_addr2_or_port2_anc(frame_num, addr_b, port_a, ctype, anchor);
2578 | } else {
2579 | DPRINT(("trying wildcarded match: %s:%d -> *:*",(void)0
2580 | addr_b_str, port_b))(void)0;
2581 | conversation = conversation_lookup_no_addr2_or_port2_anc(frame_num, addr_b, port_b, ctype, anchor);
2582 | }
2583 | if (conversation != NULL((void*)0)) {
2584 | /*
2585 | * If this is for a connection-oriented protocol, set the
2586 | * second address for this conversation to address A, as
2587 | * that's the address that matched the wildcarded second
2588 | * address for this conversation, and set the second port
2589 | * for this conversation to port A, as that's the port
2590 | * that matched the wildcarded second port for this
2591 | * conversation.
2592 | */
2593 | DPRINT(("match found"))(void)0;
2594 | if (ctype != CONVERSATION_UDP)
2595 | {
2596 | if (!(conversation->options & CONVERSATION_TEMPLATE0x08))
2597 | {
2598 | conversation_set_addr2(conversation, addr_a);
2599 | conversation_set_port2(conversation, port_a);
2600 | }
2601 | else
2602 | {
2603 | conversation = conversation_create_from_template(conversation, addr_a, port_a);
2604 | }
2605 | }
2606 | goto end;
2607 | }
2608 | }
2609 |
2610 | if (options & NO_PORT_X0x00040000) {
2611 | /*
2612 | * Search for conversations between two addresses, strictly
2613 | */
2614 | DPRINT(("trying exact match: %s -> %s",(void)0
2615 | addr_a_str, addr_b_str))(void)0;
2616 | conversation = conversation_lookup_no_ports_anc(frame_num, addr_a, addr_b, ctype, anchor);
2617 |
2618 | if (conversation != NULL((void*)0)) {
2619 | DPRINT(("match found"))(void)0;
2620 | goto end;
2621 | }
2622 | else {
2623 | conversation = conversation_lookup_no_ports_anc(frame_num, addr_b, addr_a, ctype, anchor);
2624 | if (conversation != NULL((void*)0)) {
2625 | DPRINT(("match found"))(void)0;
2626 | goto end;
2627 | }
2628 | }
2629 | }
2630 |
2631 | DPRINT(("no matches found"))(void)0;
2632 |
2633 | /*
2634 | * We found no conversation.
2635 | */
2636 | conversation = NULL((void*)0);
2637 |
2638 | end:
2639 |
2640 | DINSTR(wmem_free(NULL, addr_a_str))(void)0;
2641 | DINSTR(wmem_free(NULL, addr_b_str))(void)0;
2642 | return conversation;
2643 | }
2644 |
2645 | conversation_t *
2646 | find_conversation_deinterlacer(const uint32_t frame_num, const address *addr_a, const address *addr_b,
2647 | const conversation_type ctype, const uint32_t key_a, const uint32_t key_b, const uint32_t key_c)
2648 | {
2649 | conversation_t *conversation, *other_conv;
2650 |
2651 | conversation = conversation_lookup_deinterlacer(frame_num, addr_a, addr_b, ctype, key_a, key_b, key_c);
2652 |
2653 | other_conv = conversation_lookup_deinterlacer(frame_num, addr_b, addr_a, ctype, key_a, key_b, key_c);
2654 | if (other_conv != NULL((void*)0)) {
2655 | if (conversation != NULL((void*)0)) {
2656 | if(other_conv->conv_index > conversation->conv_index) {
2657 | conversation = other_conv;
2658 | }
2659 | }
2660 | else {
2661 | conversation = other_conv;
2662 | }
2663 | }
2664 |
2665 | return conversation;
2666 | }
2667 |
2668 | conversation_t *
2669 | find_conversation_deinterlacer_pinfo(const packet_info *pinfo)
2670 | {
2671 | conversation_t *conv=NULL((void*)0);
2672 | unsigned dr_conv_type; /* deinterlacer conv type */
2673 | uint32_t dtlc_iface = 0;
2674 | uint32_t dtlc_vlan = 0;
2675 |
2676 | /* evaluate the execution context: user pref, interface, VLAN */
2677 | if(prefs.conversation_deinterlacing_key>0) {
2678 | if(prefs.conversation_deinterlacing_key&CONV_DEINT_KEY_INTERFACE0x02 &&
2679 | pinfo->rec->presence_flags & WTAP_HAS_INTERFACE_ID0x00000004) {
2680 |
2681 | if(prefs.conversation_deinterlacing_key&CONV_DEINT_KEY_VLAN0x08 &&
2682 | pinfo->vlan_id>0) {
2683 |
2684 | dr_conv_type = CONVERSATION_ETH_IV;
2685 | dtlc_vlan = pinfo->vlan_id;
2686 | }
2687 | else {
2688 | dr_conv_type = CONVERSATION_ETH_IN;
2689 | }
2690 | dtlc_iface = pinfo->rec->rec_header.packet_header.interface_id;
2691 | }
2692 | else {
2693 | if(prefs.conversation_deinterlacing_key&CONV_DEINT_KEY_VLAN0x08 &&
2694 | pinfo->vlan_id>0) {
2695 |
2696 | dr_conv_type = CONVERSATION_ETH_NV;
2697 | dtlc_vlan = pinfo->vlan_id;
2698 | }
2699 | else {
2700 | dr_conv_type = CONVERSATION_ETH_NN;
2701 | }
2702 | }
2703 |
2704 | conv = find_conversation_deinterlacer(pinfo->num, &pinfo->dl_src, &pinfo->dl_dst, dr_conv_type, dtlc_iface, dtlc_vlan , 0);
2705 | }
2706 |
2707 | return conv;
2708 | }
2709 |
2710 | conversation_t *
2711 | find_conversation_by_id(const uint32_t frame, const conversation_type ctype, const uint32_t id)
2712 | {
2713 | conversation_element_t elements[2] = {
2714 | { CE_UINT, .uint_val = id },
2715 | { CE_CONVERSATION_TYPE, .conversation_type_val = ctype }
2716 | };
2717 |
2718 | return conversation_lookup_hashtable(conversation_hashtable_id, frame, elements);
2719 | }
2720 |
2721 | static gboolean
2722 | find_conversation_by_index(void *key _U___attribute__((unused)), void *value, void *user_data)
2723 | {
2724 | uint32_t convid = GPOINTER_TO_UINT(user_data)((guint) (gulong) (user_data));
2725 | conversation_t *conv = (conversation_t*)value;
2726 | if (conv->conv_index == convid) {
2727 | return TRUE(!(0));
2728 | }
2729 | return FALSE(0);
2730 | }
2731 |
2732 | conversation_t *
2733 | find_conversation_err_pkts(const uint32_t frame, const conversation_type ctype, const uint32_t id, const uint32_t rid)
2734 | {
2735 | conversation_element_t elements[3] = {
2736 | { CE_UINT, .uint_val = id },
2737 | { CE_UINT, .uint_val = rid },
2738 | { CE_CONVERSATION_TYPE, .conversation_type_val = ctype }
2739 | };
2740 |
2741 | return conversation_lookup_hashtable(conversation_hashtable_err_pkts, frame, elements);
2742 | }
2743 |
2744 | void
2745 | conversation_add_proto_data(conversation_t *conv, const int proto, void *proto_data)
2746 | {
2747 | if (conv == NULL((void*)0)) {
2748 | REPORT_DISSECTOR_BUG("%s: Can't add proto data to a NULL conversation.", proto_get_protocol_name(proto))proto_report_dissector_bug("%s: Can't add proto data to a NULL conversation." , proto_get_protocol_name(proto));
2749 | }
2750 | /* Add it to the list of items for this conversation. */
2751 | if (conv->data_list == NULL((void*)0))
2752 | conv->data_list = wmem_tree_new(wmem_file_scope());
2753 |
2754 | wmem_tree_insert32(conv->data_list, proto, proto_data);
2755 | }
2756 |
2757 | void *
2758 | conversation_get_proto_data(const conversation_t *conv, const int proto)
2759 | {
2760 | if (conv == NULL((void*)0)) {
2761 | REPORT_DISSECTOR_BUG("%s: Can't get proto from a NULL conversation.", proto_get_protocol_name(proto))proto_report_dissector_bug("%s: Can't get proto from a NULL conversation." , proto_get_protocol_name(proto));
2762 | }
2763 | /* No tree created yet */
2764 | if (conv->data_list == NULL((void*)0)) {
2765 | return NULL((void*)0);
2766 | }
2767 |
2768 | return wmem_tree_lookup32(conv->data_list, proto);
2769 | }
2770 |
2771 | void
2772 | conversation_delete_proto_data(conversation_t *conv, const int proto)
2773 | {
2774 | if (conv == NULL((void*)0)) {
2775 | REPORT_DISSECTOR_BUG("%s: Can't delete a NULL conversation.", proto_get_protocol_name(proto))proto_report_dissector_bug("%s: Can't delete a NULL conversation." , proto_get_protocol_name(proto));
2776 | }
2777 | if (conv->data_list != NULL((void*)0))
2778 | wmem_tree_remove32(conv->data_list, proto);
2779 | }
2780 |
2781 | void
2782 | conversation_set_dissector_from_frame_number(conversation_t *conversation,
2783 | const uint32_t starting_frame_num, const dissector_handle_t handle)
2784 | {
2785 | if (!conversation->dissector_tree) {
2786 | conversation->dissector_tree = wmem_tree_new(wmem_file_scope());
2787 | }
2788 | wmem_tree_insert32(conversation->dissector_tree, starting_frame_num, (void *)handle);
2789 | }
2790 |
2791 | void
2792 | conversation_set_dissector(conversation_t *conversation, const dissector_handle_t handle)
2793 | {
2794 | conversation_set_dissector_from_frame_number(conversation, 0, handle);
2795 | }
2796 |
2797 | dissector_handle_t
2798 | conversation_get_dissector(conversation_t *conversation, const uint32_t frame_num)
2799 | {
2800 | if (!conversation->dissector_tree) {
2801 | return NULL((void*)0);
2802 | }
2803 | return (dissector_handle_t)wmem_tree_lookup32_le(conversation->dissector_tree, frame_num);
2804 | }
2805 |
2806 | static bool_Bool
2807 | try_conversation_call_dissector_helper(conversation_t *conversation, bool_Bool* dissector_success,
2808 | tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
2809 | {
2810 | if (!conversation->dissector_tree) {
2811 | return false0;
2812 | }
2813 |
2814 | int ret;
2815 | dissector_handle_t handle = (dissector_handle_t)wmem_tree_lookup32_le(
2816 | conversation->dissector_tree, pinfo->num);
2817 | if (handle == NULL((void*)0)) {
2818 | return false0;
2819 | }
2820 |
2821 | ret = call_dissector_only(handle, tvb, pinfo, tree, data);
2822 |
2823 | /* Let the caller decide what to do with success or rejection */
2824 | (*dissector_success) = (ret != 0);
2825 |
2826 | return true1;
2827 | }
2828 |
2829 | /*
2830 | * Given two address/port pairs for a packet, search for a matching
2831 | * conversation and, if found and it has a conversation dissector,
2832 | * call that dissector and return true, otherwise return false.
2833 | *
2834 | * This helper uses call_dissector_only which will NOT call the default
2835 | * "data" dissector if the packet was rejected.
2836 | * Our caller is responsible to call the data dissector explicitly in case
2837 | * this function returns false.
2838 | */
2839 | bool_Bool
2840 | try_conversation_dissector(const address *addr_a, const address *addr_b, const conversation_type ctype,
2841 | const uint32_t port_a, const uint32_t port_b, tvbuff_t *tvb, packet_info *pinfo,
2842 | proto_tree *tree, void* data, const unsigned options)
2843 | {
2844 | conversation_t *conversation;
2845 | bool_Bool dissector_success;
2846 |
2847 | /*
2848 | * Verify that the correct options are used, if any.
2849 | */
2850 | DISSECTOR_ASSERT_HINT((options == 0) || (options & NO_MASK_B), "Use NO_ADDR_B and/or NO_PORT_B as option")((void) (((options == 0) || (options & 0xFFFF0000)) ? (void )0 : (proto_report_dissector_bug("%s:%u: failed assertion \"%s\" (%s)" , "epan/conversation.c", 2850, "(options == 0) || (options & 0xFFFF0000)" , "Use NO_ADDR_B and/or NO_PORT_B as option"))));
2851 |
2852 | /* Try each mode based on option flags */
2853 | conversation = find_conversation(pinfo->num, addr_a, addr_b, ctype, port_a, port_b, 0);
2854 | if (conversation != NULL((void*)0)) {
2855 | if (try_conversation_call_dissector_helper(conversation, &dissector_success, tvb, pinfo, tree, data))
2856 | return dissector_success;
2857 | }
2858 |
2859 | if (options & NO_ADDR_B0x00010000) {
2860 | conversation = find_conversation(pinfo->num, addr_a, addr_b, ctype, port_a, port_b, NO_ADDR_B0x00010000);
2861 | if (conversation != NULL((void*)0)) {
2862 | if (try_conversation_call_dissector_helper(conversation, &dissector_success, tvb, pinfo, tree, data))
2863 | return dissector_success;
2864 | }
2865 | }
2866 |
2867 | if (options & NO_PORT_B0x00020000) {
2868 | conversation = find_conversation(pinfo->num, addr_a, addr_b, ctype, port_a, port_b, NO_PORT_B0x00020000);
2869 | if (conversation != NULL((void*)0)) {
2870 | if (try_conversation_call_dissector_helper(conversation, &dissector_success, tvb, pinfo, tree, data))
2871 | return dissector_success;
2872 | }
2873 | }
2874 |
2875 | if (options & (NO_ADDR_B0x00010000|NO_PORT_B0x00020000)) {
2876 | conversation = find_conversation(pinfo->num, addr_a, addr_b, ctype, port_a, port_b, NO_ADDR_B0x00010000|NO_PORT_B0x00020000);
2877 | if (conversation != NULL((void*)0)) {
2878 | if (try_conversation_call_dissector_helper(conversation, &dissector_success, tvb, pinfo, tree, data))
2879 | return dissector_success;
2880 | }
2881 | }
2882 |
2883 | return false0;
2884 | }
2885 |
2886 | /*
2887 | * Similar to try_conversation_dissector() with the particularity of calling
2888 | * find_conversation_strat() in place of find_conversation() everywhere.
2889 | */
2890 | bool_Bool
2891 | try_conversation_dissector_strat(packet_info *pinfo, const conversation_type ctype,
2892 | tvbuff_t *tvb, proto_tree *tree, void* data, const unsigned options, const bool_Bool direction)
2893 | {
2894 | conversation_t *conversation;
2895 | bool_Bool dissector_success;
2896 |
2897 | /*
2898 | * Verify that the correct options are used, if any.
2899 | */
2900 | DISSECTOR_ASSERT_HINT((options == 0) || (options & NO_MASK_B), "Use NO_ADDR_B and/or NO_PORT_B as option")((void) (((options == 0) || (options & 0xFFFF0000)) ? (void )0 : (proto_report_dissector_bug("%s:%u: failed assertion \"%s\" (%s)" , "epan/conversation.c", 2900, "(options == 0) || (options & 0xFFFF0000)" , "Use NO_ADDR_B and/or NO_PORT_B as option"))));
2901 |
2902 | /* Try each mode based on option flags */
2903 | conversation = find_conversation_strat(pinfo, ctype, 0, direction);
2904 | if (conversation != NULL((void*)0)) {
2905 | if (try_conversation_call_dissector_helper(conversation, &dissector_success, tvb, pinfo, tree, data))
2906 | return dissector_success;
2907 | }
2908 |
2909 | if (options & NO_ADDR_B0x00010000) {
2910 | conversation = find_conversation_strat(pinfo, ctype, NO_ADDR_B0x00010000, direction);
2911 | if (conversation != NULL((void*)0)) {
2912 | if (try_conversation_call_dissector_helper(conversation, &dissector_success, tvb, pinfo, tree, data))
2913 | return dissector_success;
2914 | }
2915 | }
2916 |
2917 | if (options & NO_PORT_B0x00020000) {
2918 | conversation = find_conversation_strat(pinfo, ctype, NO_PORT_B0x00020000, direction);
2919 | if (conversation != NULL((void*)0)) {
2920 | if (try_conversation_call_dissector_helper(conversation, &dissector_success, tvb, pinfo, tree, data)) {
2921 | return dissector_success;
2922 | }
2923 | }
2924 |
2925 | }
2926 |
2927 | if (options & (NO_ADDR_B0x00010000|NO_PORT_B0x00020000)) {
2928 | conversation = find_conversation_strat(pinfo, ctype, NO_ADDR_B0x00010000|NO_PORT_B0x00020000, direction);
2929 | if (conversation != NULL((void*)0)) {
2930 | if (try_conversation_call_dissector_helper(conversation, &dissector_success, tvb, pinfo, tree, data)) {
2931 | return dissector_success;
2932 | }
2933 | }
2934 | }
2935 |
2936 | return false0;
2937 | }
2938 |
2939 | bool_Bool
2940 | try_conversation_dissector_by_id(const conversation_type ctype, const uint32_t id, tvbuff_t *tvb,
2941 | packet_info *pinfo, proto_tree *tree, void* data)
2942 | {
2943 | conversation_t *conversation;
2944 |
2945 | conversation = find_conversation_by_id(pinfo->num, ctype, id);
2946 |
2947 | if (conversation != NULL((void*)0)) {
2948 | if (!conversation->dissector_tree) {
2949 | return false0;
2950 | }
2951 |
2952 | int ret;
2953 | dissector_handle_t handle = (dissector_handle_t)wmem_tree_lookup32_le(conversation->dissector_tree, pinfo->num);
2954 |
2955 | if (handle == NULL((void*)0)) {
2956 | return false0;
2957 | }
2958 |
2959 | ret = call_dissector_only(handle, tvb, pinfo, tree, data);
2960 | if (!ret) {
2961 | /* this packet was rejected by the dissector
2962 | * so return false in case our caller wants
2963 | * to do some cleaning up.
2964 | */
2965 | return false0;
2966 | }
2967 | return true1;
2968 | }
2969 | return false0;
2970 | }
2971 |
2972 | /* Identifies a conversation ("classic" or deinterlaced) */
2973 | conversation_t *
2974 | find_conversation_strat(const packet_info *pinfo, const conversation_type ctype, const unsigned options, const bool_Bool direction)
2975 | {
2976 | conversation_t *conv=NULL((void*)0);
2977 | if(is_deinterlacing_supported(pinfo)) {
2978 | conversation_t *underlying_conv = find_conversation_deinterlacer_pinfo(pinfo);
2979 | if(underlying_conv) {
2980 | if(direction) { // reverse flow (dst to src)
2981 | conv = find_conversation_deinterlaced(pinfo->num, &pinfo->dst, &pinfo->src, ctype, pinfo->destport, pinfo->srcport, underlying_conv->conv_index, options);
2982 | }
2983 | else {
2984 | conv = find_conversation_deinterlaced(pinfo->num, &pinfo->src, &pinfo->dst, ctype, pinfo->srcport, pinfo->destport, underlying_conv->conv_index, options);
2985 | }
2986 | }
2987 | }
2988 | else {
2989 | if(direction) { // reverse flow (dst to src)
2990 | conv = find_conversation(pinfo->num, &pinfo->dst, &pinfo->src, ctype, pinfo->destport, pinfo->srcport, options);
2991 | }
2992 | else { // default (src to dst)
2993 | conv = find_conversation(pinfo->num, &pinfo->src, &pinfo->dst, ctype, pinfo->srcport, pinfo->destport, options);
2994 | }
2995 | }
2996 | return conv;
2997 | }
2998 |
2999 | /* Identifies a conversation ("classic" or deinterlaced) */
3000 | conversation_t *
3001 | find_conversation_strat_xtd(const packet_info *pinfo, const uint32_t frame_num, const address *addr_a, const address *addr_b,
3002 | const conversation_type ctype, const uint32_t port_a, const uint32_t port_b, const unsigned options)
3003 | {
3004 | conversation_t *conv=NULL((void*)0);
3005 | if(is_deinterlacing_supported(pinfo)) {
3006 | conversation_t *underlying_conv = find_conversation_deinterlacer_pinfo(pinfo);
3007 | if(underlying_conv) {
3008 | conv = find_conversation_deinterlaced(frame_num, addr_a, addr_b, ctype, port_a, port_b, underlying_conv->conv_index, options);
3009 | }
3010 | }
3011 | else {
3012 | conv = find_conversation(frame_num, addr_a, addr_b, ctype, port_a, port_b, options);
3013 | }
3014 | return conv;
3015 | }
3016 |
3017 | /** A helper function that calls find_conversation() using data from pinfo
3018 | * The frame number and addresses are taken from pinfo.
3019 | */
3020 | conversation_t *
3021 | find_conversation_pinfo(const packet_info *pinfo, const unsigned options)
3022 | {
3023 | conversation_t *conv = NULL((void*)0);
3024 |
3025 | DINSTR(char *src_str = address_to_str(NULL, &pinfo->src))(void)0;
3026 | DINSTR(char *dst_str = address_to_str(NULL, &pinfo->dst))(void)0;
3027 | DPRINT(("called for frame #%u: %s:%d -> %s:%d (ptype=%d)",(void)0
3028 | pinfo->num, src_str, pinfo->srcport,(void)0
3029 | dst_str, pinfo->destport, pinfo->ptype))(void)0;
3030 | DINDENT()(void)0;
3031 | DINSTR(wmem_free(NULL, src_str))(void)0;
3032 | DINSTR(wmem_free(NULL, dst_str))(void)0;
3033 |
3034 | /* Have we seen this conversation before? */
3035 | if (pinfo->use_conv_addr_port_endpoints) {
3036 | DISSECTOR_ASSERT(pinfo->conv_addr_port_endpoints)((void) ((pinfo->conv_addr_port_endpoints) ? (void)0 : (proto_report_dissector_bug ("%s:%u: failed assertion \"%s\"", "epan/conversation.c", 3036 , "pinfo->conv_addr_port_endpoints"))));
3037 | if ((conv = find_conversation(pinfo->num, &pinfo->conv_addr_port_endpoints->addr1, &pinfo->conv_addr_port_endpoints->addr2,
3038 | pinfo->conv_addr_port_endpoints->ctype, pinfo->conv_addr_port_endpoints->port1,
3039 | pinfo->conv_addr_port_endpoints->port2, 0)) != NULL((void*)0)) {
3040 | DPRINT(("found previous conversation for frame #%u (last_frame=%d)",(void)0
3041 | pinfo->num, conv->last_frame))(void)0;
3042 | if (pinfo->num > conv->last_frame) {
3043 | conv->last_frame = pinfo->num;
3044 | }
3045 | }
3046 | } else if (pinfo->conv_elements) {
3047 | if ((conv = find_conversation_full(pinfo->num, pinfo->conv_elements)) != NULL((void*)0)) {
3048 | DPRINT(("found previous conversation elements for frame #%u (last_frame=%d)",(void)0
3049 | pinfo->num, conv->last_frame))(void)0;
3050 | if (pinfo->num > conv->last_frame) {
3051 | conv->last_frame = pinfo->num;
3052 | }
3053 | }
3054 | } else {
3055 | if ((conv = find_conversation(pinfo->num, &pinfo->src, &pinfo->dst,
3056 | conversation_pt_to_conversation_type(pinfo->ptype), pinfo->srcport,
3057 | pinfo->destport, options)) != NULL((void*)0)) {
3058 | DPRINT(("found previous conversation for frame #%u (last_frame=%d)",(void)0
3059 | pinfo->num, conv->last_frame))(void)0;
3060 | if (pinfo->num > conv->last_frame) {
3061 | conv->last_frame = pinfo->num;
3062 | }
3063 | }
3064 | }
3065 |
3066 | DENDENT()(void)0;
3067 |
3068 | return conv;
3069 | }
3070 |
3071 | conversation_t *
3072 | find_conversation_pinfo_deinterlaced(const packet_info *pinfo, const uint32_t anchor, const unsigned options)
3073 | {
3074 | conversation_t *conv = NULL((void*)0);
3075 |
3076 | DINSTR(char *src_str = address_to_str(NULL, &pinfo->src))(void)0;
3077 | DINSTR(char *dst_str = address_to_str(NULL, &pinfo->dst))(void)0;
3078 | DPRINT(("called for frame #%u: %s:%d -> %s:%d (ptype=%d)",(void)0
3079 | pinfo->num, src_str, pinfo->srcport,(void)0
3080 | dst_str, pinfo->destport, pinfo->ptype))(void)0;
3081 | DINDENT()(void)0;
3082 | DINSTR(wmem_free(NULL, src_str))(void)0;
3083 | DINSTR(wmem_free(NULL, dst_str))(void)0;
3084 |
3085 | /* Have we seen this conversation before? */
3086 | if (pinfo->use_conv_addr_port_endpoints) {
3087 | // For example, it's reached with EAPOL/TLS over Ethernet, see Issue #21027
3088 | DISSECTOR_ASSERT(pinfo->conv_addr_port_endpoints)((void) ((pinfo->conv_addr_port_endpoints) ? (void)0 : (proto_report_dissector_bug ("%s:%u: failed assertion \"%s\"", "epan/conversation.c", 3088 , "pinfo->conv_addr_port_endpoints"))));
3089 | if ((conv = find_conversation_deinterlaced(pinfo->num, &pinfo->conv_addr_port_endpoints->addr1, &pinfo->conv_addr_port_endpoints->addr2,
3090 | pinfo->conv_addr_port_endpoints->ctype, pinfo->conv_addr_port_endpoints->port1,
3091 | pinfo->conv_addr_port_endpoints->port2, anchor, 0)) != NULL((void*)0)) {
3092 | DPRINT(("found previous conversation for frame #%u (last_frame=%d)",(void)0
3093 | pinfo->num, conv->last_frame))(void)0;
3094 | if (pinfo->num > conv->last_frame) {
3095 | conv->last_frame = pinfo->num;
3096 | }
3097 | }
3098 | } else if (pinfo->conv_elements) {
3099 | // XXX - not implemented yet. Necessary ?
3100 | } else {
3101 | if ((conv = find_conversation_deinterlaced(pinfo->num, &pinfo->src, &pinfo->dst,
3102 | conversation_pt_to_conversation_type(pinfo->ptype), pinfo->srcport,
3103 | pinfo->destport, anchor, options)) != NULL((void*)0)) {
3104 | DPRINT(("found previous conversation for frame #%u (last_frame=%d)",(void)0
3105 | pinfo->num, conv->last_frame))(void)0;
3106 | if (pinfo->num > conv->last_frame) {
3107 | conv->last_frame = pinfo->num;
3108 | }
3109 | }
3110 | }
3111 |
3112 | DENDENT()(void)0;
3113 |
3114 | return conv;
3115 | }
3116 |
3117 | /*
3118 | * Returns true when deinterlacing is supported (file format) and enabled (user pref)
3119 | * Deinterlacing is only supported for the Ethernet wtap for now.
3120 | */
3121 | bool_Bool
3122 | is_deinterlacing_supported(const packet_info *pinfo)
3123 | {
3124 | if( (pinfo->pseudo_header != NULL((void*)0))
3125 | && (pinfo->rec->rec_header.packet_header.pkt_encap == WTAP_ENCAP_ETHERNET1)
3126 | && (prefs.conversation_deinterlacing_key>0)) {
3127 | return true1;
3128 | }
3129 | return false0;
3130 | }
3131 |
3132 | conversation_t *
3133 | find_conversation_pinfo_strat(const packet_info *pinfo, const unsigned options)
3134 | {
3135 | conversation_t *conv=NULL((void*)0);
3136 |
3137 | if(is_deinterlacing_supported(pinfo)) {
3138 |
3139 | conversation_t *underlying_conv = find_conversation_deinterlacer_pinfo(pinfo);
3140 |
3141 | if(underlying_conv) {
3142 | conv = find_conversation_pinfo_deinterlaced(pinfo, underlying_conv->conv_index, options);
3143 | }
3144 | }
3145 | else {
3146 | conv = find_conversation_pinfo(pinfo, options);
3147 | }
3148 |
3149 | return conv;
3150 | }
3151 |
3152 | /** A helper function that calls find_conversation() using data from pinfo,
3153 | * as above, but somewhat simplified for being accessed from packet_list.
3154 | * The frame number and addresses are taken from pinfo.
3155 | */
3156 | conversation_t *
3157 | find_conversation_pinfo_ro(const packet_info *pinfo, const unsigned options)
3158 | {
3159 | conversation_t *conv = NULL((void*)0);
3160 |
3161 | DINSTR(char *src_str = address_to_str(NULL, &pinfo->src))(void)0;
3162 | DINSTR(char *dst_str = address_to_str(NULL, &pinfo->dst))(void)0;
3163 | DPRINT(("called for frame #%u: %s:%d -> %s:%d (ptype=%d)",(void)0
3164 | pinfo->num, src_str, pinfo->srcport,(void)0
3165 | dst_str, pinfo->destport, pinfo->ptype))(void)0;
3166 | DINDENT()(void)0;
3167 | DINSTR(wmem_free(NULL, src_str))(void)0;
3168 | DINSTR(wmem_free(NULL, dst_str))(void)0;
3169 |
3170 | /* Have we seen this conversation before? */
3171 | if (pinfo->use_conv_addr_port_endpoints) {
3172 | DISSECTOR_ASSERT(pinfo->conv_addr_port_endpoints)((void) ((pinfo->conv_addr_port_endpoints) ? (void)0 : (proto_report_dissector_bug ("%s:%u: failed assertion \"%s\"", "epan/conversation.c", 3172 , "pinfo->conv_addr_port_endpoints"))));
3173 | if ((conv = find_conversation(pinfo->num, &pinfo->conv_addr_port_endpoints->addr1, &pinfo->conv_addr_port_endpoints->addr2,
3174 | pinfo->conv_addr_port_endpoints->ctype, pinfo->conv_addr_port_endpoints->port1,
3175 | pinfo->conv_addr_port_endpoints->port2, 0)) != NULL((void*)0)) {
3176 | DPRINT(("found previous conversation for frame #%u (last_frame=%d)",(void)0
3177 | pinfo->num, conv->last_frame))(void)0;
3178 | }
3179 | } else if (pinfo->conv_elements) {
3180 | if ((conv = find_conversation_full(pinfo->num, pinfo->conv_elements)) != NULL((void*)0)) {
3181 | DPRINT(("found previous conversation elements for frame #%u (last_frame=%d)",(void)0
3182 | pinfo->num, conv->last_frame))(void)0;
3183 | }
3184 | } else if ((conv = find_conversation_strat(pinfo, conversation_pt_to_conversation_type(pinfo->ptype), options, false0)) != NULL((void*)0)) {
3185 | DPRINT(("found previous conversation for frame #%u (last_frame=%d)",(void)0
3186 | pinfo->num, conv->last_frame))(void)0;
3187 | }
3188 | /* If none of the above found any ordinary conversation,
3189 | * we might be dealing with an error packet referencing/carrying a known conversation.
3190 | * ICMP Type 3/11 are good examples, give them a chance to be identified.
3191 | * Note, any Transport protocol might be updated to allow this mechanism to work.
3192 | */
3193 | else if( (pinfo->track_ctype>0) ) {
3194 |
3195 | /* reference id */
3196 | uint32_t conv_index = 0;
3197 |
3198 | /* Parse all keys and find the one matching id and ctype,
3199 | * the reference id is what we are looking for.
3200 | */
3201 | wmem_list_t *err_pkts_keys = wmem_map_get_keys(NULL((void*)0), conversation_hashtable_err_pkts);
3202 | for (wmem_list_frame_t *cur_frame = wmem_list_head(err_pkts_keys ); cur_frame; cur_frame = wmem_list_frame_next(cur_frame)) {
3203 | conversation_element_t *cet = (conversation_element_t *)wmem_list_frame_data(cur_frame);
3204 | if(cet) {
3205 | if( (cet[2].conversation_type_val == pinfo->track_ctype) && (cet[0].uint_val == pinfo->stream_id) ) {
3206 | conv_index = cet[1].uint_val;
3207 | break;
3208 | }
3209 | }
3210 | }
3211 | wmem_destroy_list(err_pkts_keys);
3212 |
3213 | /* Now, bring the transport conversation as we know its conv_index.
3214 | * Note: the way conversations are added (starting from lower layers),
3215 | * it's currently not possible to see a transport conversation
3216 | * with conv_index with value 0.
3217 | * XXX - Check if that is also true for PDU.
3218 | */
3219 | if(conv_index>0) {
3220 | conversation_t *tsconv = NULL((void*)0);
3221 |
3222 | /* If a deinterlacing key was requested, search for the conversation
3223 | * in the deinterlaced version of the "addr_port" table.
3224 | * XXX - as this check is becoming redundant, isolate it in a function ?
3225 | */
3226 | if(is_deinterlacing_supported(pinfo)) {
3227 | tsconv = wmem_map_find(conversation_hashtable_exact_addr_port_anc, find_conversation_by_index, GUINT_TO_POINTER(conv_index)((gpointer) (gulong) (conv_index)));
3228 | }
3229 | else {
3230 | tsconv = wmem_map_find(conversation_hashtable_exact_addr_port, find_conversation_by_index, GUINT_TO_POINTER(conv_index)((gpointer) (gulong) (conv_index)));
3231 | }
3232 | if(tsconv) {
3233 | conv = tsconv;
3234 | }
3235 | }
3236 | }
3237 | /* else: something is either not implemented or not handled */
3238 |
3239 | DENDENT()(void)0;
3240 |
3241 | return conv;
3242 | }
3243 |
3244 | /* A helper function that calls find_conversation() and, if a conversation is
3245 | * not found, calls conversation_new().
3246 | * The frame number and addresses are taken from pinfo.
3247 | * No options are used, though we could extend this API to include an options
3248 | * parameter.
3249 | */
3250 | conversation_t *
3251 | find_or_create_conversation(const packet_info *pinfo)
3252 | {
3253 | conversation_t *conv=NULL((void*)0);
3254 |
3255 | /* Have we seen this conversation before? */
3256 | if ((conv = find_conversation_pinfo(pinfo, 0)) == NULL((void*)0)) {
3257 | /* No, this is a new conversation. */
3258 | DPRINT(("did not find previous conversation for frame #%u",(void)0
3259 | pinfo->num))(void)0;
3260 | DINDENT()(void)0;
3261 | if (pinfo->use_conv_addr_port_endpoints) {
3262 | conv = conversation_new(pinfo->num, &pinfo->conv_addr_port_endpoints->addr1, &pinfo->conv_addr_port_endpoints->addr2,
3263 | pinfo->conv_addr_port_endpoints->ctype, pinfo->conv_addr_port_endpoints->port1,
3264 | pinfo->conv_addr_port_endpoints->port2, 0);
3265 | } else if (pinfo->conv_elements) {
3266 | conv = conversation_new_full(pinfo->num, pinfo->conv_elements);
3267 | } else {
3268 | conv = conversation_new(pinfo->num, &pinfo->src,
3269 | &pinfo->dst, conversation_pt_to_conversation_type(pinfo->ptype),
3270 | pinfo->srcport, pinfo->destport, 0);
3271 | }
3272 | DENDENT()(void)0;
3273 | }
3274 |
3275 | return conv;
3276 | }
3277 |
3278 | conversation_t *
3279 | find_or_create_conversation_deinterlaced(const packet_info *pinfo, const uint32_t conv_index)
3280 | {
3281 | conversation_t *conv=NULL((void*)0);
3282 |
3283 | /* Have we seen this conversation before? */
3284 | if ((conv = find_conversation_pinfo_deinterlaced(pinfo, conv_index, 0)) == NULL((void*)0)) {
3285 | /* No, this is a new conversation. */
3286 | DPRINT(("did not find previous conversation for frame #%u",(void)0
3287 | pinfo->num))(void)0;
3288 | DINDENT()(void)0;
3289 | if (pinfo->use_conv_addr_port_endpoints) {
3290 | conv = conversation_new_deinterlaced(pinfo->num, &pinfo->conv_addr_port_endpoints->addr1, &pinfo->conv_addr_port_endpoints->addr2,
3291 | pinfo->conv_addr_port_endpoints->ctype, pinfo->conv_addr_port_endpoints->port1,
3292 | pinfo->conv_addr_port_endpoints->port2, conv_index, 0);
3293 | } else if (pinfo->conv_elements) {
3294 | conv = conversation_new_full(pinfo->num, pinfo->conv_elements);
3295 | } else {
3296 | conv = conversation_new_deinterlaced(pinfo->num, &pinfo->src, &pinfo->dst,
3297 | conversation_pt_to_conversation_type(pinfo->ptype),
3298 | pinfo->srcport, pinfo->destport, conv_index, 0);
3299 | }
3300 | DENDENT()(void)0;
3301 | }
3302 |
3303 | return conv;
3304 | }
3305 |
3306 | conversation_t *
3307 | find_or_create_conversation_strat(const packet_info *pinfo)
3308 | {
3309 | conversation_t *conv=NULL((void*)0);
1 | 'conv' initialized to a null pointer value | →
3310 |
3311 | if(is_deinterlacing_supported(pinfo)) {
2 | ← | Taking true branch | →
3312 | conversation_t *underlying_conv = find_conversation_deinterlacer_pinfo(pinfo);
3313 | if(underlying_conv) {
3 | ← | Assuming 'underlying_conv' is null | →
4 | ← | Taking false branch | →
3314 | conv = find_or_create_conversation_deinterlaced(pinfo, underlying_conv->conv_index);
3315 | }
3316 | }
3317 | else {
3318 | conv = find_or_create_conversation(pinfo);
3319 | }
3320 |
3321 | return conv;
5 | ← | Null returned from a function that is expected to return a non-null value
3322 | }
3323 |
3324 | conversation_t *
3325 | find_or_create_conversation_by_id(packet_info *pinfo, const conversation_type ctype, const uint32_t id)
3326 | {
3327 | conversation_t *conv=NULL((void*)0);
3328 |
3329 | /* Have we seen this conversation before? */
3330 | if ((conv = find_conversation_by_id(pinfo->num, ctype, id)) == NULL((void*)0)) {
3331 | /* No, this is a new conversation. */
3332 | DPRINT(("did not find previous conversation for frame #%u",(void)0
3333 | pinfo->num))(void)0;
3334 | DINDENT()(void)0;
3335 | conv = conversation_new_by_id(pinfo->num, ctype, id);
3336 | DENDENT()(void)0;
3337 | }
3338 |
3339 | return conv;
3340 | }
3341 |
3342 | void
3343 | conversation_set_conv_addr_port_endpoints(struct _packet_info *pinfo, address* addr1, address* addr2,
3344 | conversation_type ctype, uint32_t port1, uint32_t port2)
3345 | {
3346 | pinfo->conv_addr_port_endpoints = wmem_new0(pinfo->pool, struct conversation_addr_port_endpoints)((struct conversation_addr_port_endpoints*)wmem_alloc0((pinfo ->pool), sizeof(struct conversation_addr_port_endpoints)));
3347 |
3348 | if (addr1 != NULL((void*)0)) {
3349 | copy_address_wmem(pinfo->pool, &pinfo->conv_addr_port_endpoints->addr1, addr1);
3350 | }
3351 | if (addr2 != NULL((void*)0)) {
3352 | copy_address_wmem(pinfo->pool, &pinfo->conv_addr_port_endpoints->addr2, addr2);
3353 | }
3354 |
3355 | pinfo->conv_addr_port_endpoints->ctype = ctype;
3356 | pinfo->conv_addr_port_endpoints->port1 = port1;
3357 | pinfo->conv_addr_port_endpoints->port2 = port2;
3358 |
3359 | pinfo->use_conv_addr_port_endpoints = true1;
3360 | }
3361 |
3362 | void
3363 | conversation_set_elements_by_id(struct _packet_info *pinfo, conversation_type ctype, uint32_t id)
3364 | {
3365 | pinfo->conv_elements = wmem_alloc0(pinfo->pool, sizeof(conversation_element_t) * 2);
3366 | pinfo->conv_elements[0].type = CE_UINT;
3367 | pinfo->conv_elements[0].uint_val = id;
3368 | pinfo->conv_elements[1].type = CE_CONVERSATION_TYPE;
3369 | pinfo->conv_elements[1].conversation_type_val = ctype;
3370 | }
3371 |
3372 | uint32_t
3373 | conversation_get_id_from_elements(struct _packet_info *pinfo, conversation_type ctype, const unsigned options)
3374 | {
3375 | if (pinfo->conv_elements == NULL((void*)0)) {
3376 | return 0;
3377 | }
3378 |
3379 | if (pinfo->conv_elements[0].type != CE_UINT || pinfo->conv_elements[1].type != CE_CONVERSATION_TYPE) {
3380 | return 0;
3381 | }
3382 |
3383 | if ((pinfo->conv_elements[1].conversation_type_val != ctype) && ((options & USE_LAST_ENDPOINT0x08) != USE_LAST_ENDPOINT0x08)) {
3384 | return 0;
3385 | }
3386 |
3387 | return pinfo->conv_elements[0].uint_val;
3388 | }
3389 |
3390 | wmem_map_t *
3391 | get_conversation_hashtables(void)
3392 | {
3393 | return conversation_hashtable_element_list;
3394 | }
3395 |
3396 | const address*
3397 | conversation_key_addr1(const conversation_element_t *key)
3398 | {
3399 | const address *addr = &null_address_;
3400 | if (key[ADDR1_IDX].type == CE_ADDRESS) {
3401 | addr = &key[ADDR1_IDX].addr_val;
3402 | }
3403 | return addr;
3404 | }
3405 |
3406 | uint32_t
3407 | conversation_key_port1(const conversation_element_t * key)
3408 | {
3409 | uint32_t port = 0;
3410 | if (key[ADDR1_IDX].type == CE_ADDRESS && key[PORT1_IDX].type == CE_PORT) {
3411 | port = key[PORT1_IDX].port_val;
3412 | }
3413 | return port;
3414 | }
3415 |
3416 | const address*
3417 | conversation_key_addr2(const conversation_element_t * key)
3418 | {
3419 | const address *addr = &null_address_;
3420 | if (key[ADDR1_IDX].type == CE_ADDRESS && key[PORT1_IDX].type == CE_PORT && key[ADDR2_IDX].type == CE_ADDRESS) {
3421 | addr = &key[ADDR2_IDX].addr_val;
3422 | }
3423 | return addr;
3424 | }
3425 |
3426 | uint32_t
3427 | conversation_key_port2(const conversation_element_t * key)
3428 | {
3429 | uint32_t port = 0;
3430 | if (key[ADDR1_IDX].type == CE_ADDRESS && key[PORT1_IDX].type == CE_PORT) {
3431 | if (key[ADDR2_IDX].type == CE_ADDRESS && key[PORT2_IDX].type == CE_PORT) {
3432 | // Exact
3433 | port = key[PORT2_IDX].port_val;
3434 | } else if (key[PORT2_NO_ADDR2_IDX].type == CE_PORT) {
3435 | // No addr 2
3436 | port = key[PORT2_NO_ADDR2_IDX].port_val;
3437 | }
3438 | }
3439 | return port;
3440 | }
3441 |
3442 | WS_DLL_PUBLIC__attribute__ ((visibility ("default"))) extern
3443 | conversation_type conversation_pt_to_conversation_type(port_type pt)
3444 | {
3445 | switch (pt)
3446 | {
3447 | case PT_NONE:
3448 | return CONVERSATION_NONE;
3449 | case PT_SCTP:
3450 | return CONVERSATION_SCTP;
3451 | case PT_TCP:
3452 | return CONVERSATION_TCP;
3453 | case PT_UDP:
3454 | return CONVERSATION_UDP;
3455 | case PT_DCCP:
3456 | return CONVERSATION_DCCP;
3457 | case PT_IPX:
3458 | return CONVERSATION_IPX;
3459 | case PT_DDP:
3460 | return CONVERSATION_DDP;
3461 | case PT_IDP:
3462 | return CONVERSATION_IDP;
3463 | case PT_USB:
3464 | return CONVERSATION_USB;
3465 | case PT_I2C:
3466 | /* XXX - this doesn't currently have conversations */
3467 | return CONVERSATION_I2C;
3468 | case PT_IBQP:
3469 | return CONVERSATION_IBQP;
3470 | case PT_BLUETOOTH:
3471 | return CONVERSATION_BLUETOOTH;
3472 | case PT_IWARP_MPA:
3473 | return CONVERSATION_IWARP_MPA;
3474 | case PT_MCTP:
3475 | return CONVERSATION_MCTP;
3476 | }
3477 |
3478 | DISSECTOR_ASSERT(false)((void) ((0) ? (void)0 : (proto_report_dissector_bug("%s:%u: failed assertion \"%s\"" , "epan/conversation.c", 3478, "0"))));
3479 | return CONVERSATION_NONE;
3480 | }
3481 |
3482 | WS_DLL_PUBLIC__attribute__ ((visibility ("default"))) extern
3483 | endpoint_type conversation_pt_to_endpoint_type(port_type pt)
3484 | {
3485 | switch (pt)
3486 | {
3487 | case PT_NONE:
3488 | return ENDPOINT_NONECONVERSATION_NONE;
3489 | case PT_SCTP:
3490 | return ENDPOINT_SCTPCONVERSATION_SCTP;
3491 | case PT_TCP:
3492 | return ENDPOINT_TCPCONVERSATION_TCP;
3493 | case PT_UDP:
3494 | return ENDPOINT_UDPCONVERSATION_UDP;
3495 | case PT_DCCP:
3496 | return ENDPOINT_DCCPCONVERSATION_DCCP;
3497 | case PT_IPX:
3498 | return ENDPOINT_IPXCONVERSATION_IPX;
3499 | case PT_DDP:
3500 | return ENDPOINT_DDPCONVERSATION_DDP;
3501 | case PT_IDP:
3502 | return ENDPOINT_IDPCONVERSATION_IDP;
3503 | case PT_USB:
3504 | return ENDPOINT_USBCONVERSATION_USB;
3505 | case PT_I2C:
3506 | /* XXX - this doesn't have ports */
3507 | return ENDPOINT_I2CCONVERSATION_I2C;
3508 | case PT_IBQP:
3509 | return ENDPOINT_IBQPCONVERSATION_IBQP;
3510 | case PT_BLUETOOTH:
3511 | return ENDPOINT_BLUETOOTHCONVERSATION_BLUETOOTH;
3512 | case PT_IWARP_MPA:
3513 | return ENDPOINT_IWARP_MPACONVERSATION_IWARP_MPA;
3514 | case PT_MCTP:
3515 | return ENDPOINT_MCTPCONVERSATION_MCTP;
3516 | }
3517 |
3518 | DISSECTOR_ASSERT(false)((void) ((0) ? (void)0 : (proto_report_dissector_bug("%s:%u: failed assertion \"%s\"" , "epan/conversation.c", 3518, "0"))));
3519 | return ENDPOINT_NONECONVERSATION_NONE;
3520 | }
3521 |
3522 | /*
3523 | * Editor modelines - https://www.wireshark.org/tools/modelines.html
3524 | *
3525 | * Local variables:
3526 | * c-basic-offset: 4
3527 | * tab-width: 8
3528 | * indent-tabs-mode: nil
3529 | * End:
3530 | *
3531 | * vi: set shiftwidth=4 tabstop=8 expandtab:
3532 | * :indentSize=4:tabSize=8:noTabs=true:
3533 | */