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 #include <glib.h>
15 #include "packet.h"
16 #include "to_str.h"
17 #include "conversation.h"
18
19 /* define DEBUG_CONVERSATION for pretty debug printing */
20 /* #define DEBUG_CONVERSATION */
21 #include "conversation_debug.h"
22
23 #ifdef DEBUG_CONVERSATION
24 int _debug_conversation_indent = 0;
25 #endif
26
27 struct endpoint {
28 address addr1;
29 address addr2;
30 endpoint_type etype;
31 guint32 port1;
32 guint32 port2;
33 guint options;
34 };
35
36 struct conversation_key {
37 struct conversation_key *next;
38 address addr1;
39 address addr2;
40 endpoint_type etype;
41 guint32 port1;
42 guint32 port2;
43 };
44
45 /*
46 * Hash table for conversations with no wildcards.
47 */
48 static wmem_map_t *conversation_hashtable_exact = NULL;
49
50 /*
51 * Hash table for conversations with one wildcard address.
52 */
53 static wmem_map_t *conversation_hashtable_no_addr2 = NULL;
54
55 /*
56 * Hash table for conversations with one wildcard port.
57 */
58 static wmem_map_t *conversation_hashtable_no_port2 = NULL;
59
60 /*
61 * Hash table for conversations with one wildcard address and port.
62 */
63 static wmem_map_t *conversation_hashtable_no_addr2_or_port2 = NULL;
64
65
66 static guint32 new_index;
67
68 /*
69 * Placeholder for address-less conversations.
70 */
71 static address null_address_ = ADDRESS_INIT_NONE;
72
73
74 /*
75 * Creates a new conversation with known endpoints based on a conversation
76 * created with the CONVERSATION_TEMPLATE option while keeping the
77 * conversation created with the CONVERSATION_TEMPLATE option so it can still
78 * match future connections.
79 *
80 * Passing a pointer to a conversation whose options mask does not include
81 * CONVERSATION_TEMPLATE or where the conversation's protocol type (ptype)
82 * indicates a non-connnection oriented protocol will return the conversation
83 * without changes.
84 *
85 * addr2 and port2 are used in the function if their respective conversation
86 * options bits are set (NO_ADDR2 and NO_PORT2).
87 */
88 static conversation_t *
conversation_create_from_template(conversation_t * conversation,const address * addr2,const guint32 port2)89 conversation_create_from_template(conversation_t *conversation, const address *addr2, const guint32 port2)
90 {
91 /*
92 * Add a new conversation and keep the conversation template only if the
93 * CONVERSATION_TEMPLATE bit is set for a connection oriented protocol.
94 */
95 if (conversation->options & CONVERSATION_TEMPLATE &&
96 conversation->key_ptr->etype != ENDPOINT_UDP)
97 {
98 /*
99 * Set up a new options mask where the conversation template bit and the
100 * bits for absence of a second address and port pair have been removed.
101 */
102 conversation_t *new_conversation_from_template;
103 guint options = conversation->options & ~(CONVERSATION_TEMPLATE | NO_ADDR2 | NO_PORT2);
104
105 /*
106 * Are both the NO_ADDR2 and NO_PORT2 wildcards set in the options mask?
107 */
108 if (conversation->options & NO_ADDR2 &&
109 conversation->options & NO_PORT2)
110 {
111 /*
112 * The conversation template was created without knowledge of both
113 * the second address as well as the second port. Create a new
114 * conversation with new 2nd address and 2nd port.
115 */
116 new_conversation_from_template =
117 conversation_new(conversation->setup_frame,
118 &conversation->key_ptr->addr1, addr2,
119 conversation->key_ptr->etype, conversation->key_ptr->port1,
120 port2, options);
121 }
122 else if (conversation->options & NO_PORT2)
123 {
124 /*
125 * The conversation template was created without knowledge of port 2
126 * only. Create a new conversation with new 2nd port.
127 */
128 new_conversation_from_template =
129 conversation_new(conversation->setup_frame,
130 &conversation->key_ptr->addr1, &conversation->key_ptr->addr2,
131 conversation->key_ptr->etype, conversation->key_ptr->port1,
132 port2, options);
133 }
134 else if (conversation->options & NO_ADDR2)
135 {
136 /*
137 * The conversation template was created without knowledge of address
138 * 2. Create a new conversation with new 2nd address.
139 */
140 new_conversation_from_template =
141 conversation_new(conversation->setup_frame,
142 &conversation->key_ptr->addr1, addr2,
143 conversation->key_ptr->etype, conversation->key_ptr->port1,
144 conversation->key_ptr->port2, options);
145 }
146 else
147 {
148 /*
149 * The CONVERSATION_TEMPLATE bit was set, but no other bit that the
150 * CONVERSATION_TEMPLATE bit controls is active. Just return the old
151 * conversation.
152 */
153 return conversation;
154 }
155
156 /*
157 * Set the protocol dissector used for the template conversation as
158 * the handler of the new conversation as well.
159 */
160 new_conversation_from_template->dissector_tree = conversation->dissector_tree;
161
162 return new_conversation_from_template;
163 }
164 else
165 {
166 return conversation;
167 }
168 }
169
170 /*
171 * Compute the hash value for two given address/port pairs if the match
172 * is to be exact.
173 */
174 /* https://web.archive.org/web/20070615045827/http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx#existing
175 * (formerly at http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx#existing)
176 * One-at-a-Time hash
177 */
178 guint
conversation_hash_exact(gconstpointer v)179 conversation_hash_exact(gconstpointer v)
180 {
181 const conversation_key_t key = (const conversation_key_t)v;
182 guint hash_val;
183 address tmp_addr;
184
185 hash_val = 0;
186 tmp_addr.len = 4;
187
188 hash_val = add_address_to_hash(hash_val, &key->addr1);
189
190 tmp_addr.data = &key->port1;
191 hash_val = add_address_to_hash(hash_val, &tmp_addr);
192
193 hash_val = add_address_to_hash(hash_val, &key->addr2);
194
195 tmp_addr.data = &key->port2;
196 hash_val = add_address_to_hash(hash_val, &tmp_addr);
197
198 hash_val += ( hash_val << 3 );
199 hash_val ^= ( hash_val >> 11 );
200 hash_val += ( hash_val << 15 );
201
202 return hash_val;
203 }
204
205 /*
206 * Compare two conversation keys for an exact match.
207 */
208 static gint
conversation_match_exact(gconstpointer v,gconstpointer w)209 conversation_match_exact(gconstpointer v, gconstpointer w)
210 {
211 const conversation_key_t v1 = (const conversation_key_t)v;
212 const conversation_key_t v2 = (const conversation_key_t)w;
213
214 if (v1->etype != v2->etype)
215 return 0; /* different types of port */
216
217 /*
218 * Are the first and second port 1 values the same, the first and
219 * second port 2 values the same, the first and second address
220 * 1 values the same, and the first and second address 2 values
221 * the same?
222 */
223 if (v1->port1 == v2->port1 &&
224 v1->port2 == v2->port2 &&
225 addresses_equal(&v1->addr1, &v2->addr1) &&
226 addresses_equal(&v1->addr2, &v2->addr2)) {
227 /*
228 * Yes. It's the same conversation, and the two
229 * address/port pairs are going in the same direction.
230 */
231 return 1;
232 }
233
234 /*
235 * Is the first port 2 the same as the second port 1, the first
236 * port 1 the same as the second port 2, the first address 2
237 * the same as the second address 1, and the first address 1
238 * the same as the second address 2?
239 */
240 if (v1->port2 == v2->port1 &&
241 v1->port1 == v2->port2 &&
242 addresses_equal(&v1->addr2, &v2->addr1) &&
243 addresses_equal(&v1->addr1, &v2->addr2)) {
244 /*
245 * Yes. It's the same conversation, and the two
246 * address/port pairs are going in opposite directions.
247 */
248 return 1;
249 }
250
251 /*
252 * The addresses or the ports don't match.
253 */
254 return 0;
255 }
256
257 /*
258 * Compute the hash value for two given address/port pairs if the match
259 * has a wildcard address 2.
260 */
261 static guint
conversation_hash_no_addr2(gconstpointer v)262 conversation_hash_no_addr2(gconstpointer v)
263 {
264 const conversation_key_t key = (const conversation_key_t)v;
265 guint hash_val;
266 address tmp_addr;
267
268 hash_val = 0;
269 tmp_addr.len = 4;
270
271 hash_val = add_address_to_hash(hash_val, &key->addr1);
272
273 tmp_addr.data = &key->port1;
274 hash_val = add_address_to_hash(hash_val, &tmp_addr);
275
276 tmp_addr.data = &key->port2;
277 hash_val = add_address_to_hash(hash_val, &tmp_addr);
278
279 hash_val += ( hash_val << 3 );
280 hash_val ^= ( hash_val >> 11 );
281 hash_val += ( hash_val << 15 );
282
283 return hash_val;
284 }
285
286 /*
287 * Compare two conversation keys, except for the address 2 value.
288 * We don't check both directions of the conversation - the routine
289 * doing the hash lookup has to do two searches, as the hash key
290 * will be different for the two directions.
291 */
292 static gint
conversation_match_no_addr2(gconstpointer v,gconstpointer w)293 conversation_match_no_addr2(gconstpointer v, gconstpointer w)
294 {
295 const conversation_key_t v1 = (const conversation_key_t)v;
296 const conversation_key_t v2 = (const conversation_key_t)w;
297
298 if (v1->etype != v2->etype)
299 return 0; /* different types of port */
300
301 /*
302 * Are the first and second port 1 values the same, the first and
303 * second port 2 valuess the same, and the first and second
304 * address 1 values the same?
305 */
306 if (v1->port1 == v2->port1 &&
307 v1->port2 == v2->port2 &&
308 addresses_equal(&v1->addr1, &v2->addr1)) {
309 /*
310 * Yes. It's the same conversation, and the two
311 * address/port pairs are going in the same direction.
312 */
313 return 1;
314 }
315
316 /*
317 * The addresses or the ports don't match.
318 */
319 return 0;
320 }
321
322 /*
323 * Compute the hash value for two given address/port pairs if the match
324 * has a wildcard port 2.
325 */
326 static guint
conversation_hash_no_port2(gconstpointer v)327 conversation_hash_no_port2(gconstpointer v)
328 {
329 const conversation_key_t key = (const conversation_key_t)v;
330 guint hash_val;
331 address tmp_addr;
332
333 hash_val = 0;
334 tmp_addr.len = 4;
335
336 hash_val = add_address_to_hash(hash_val, &key->addr1);
337
338 tmp_addr.data = &key->port1;
339 hash_val = add_address_to_hash(hash_val, &tmp_addr);
340
341 hash_val = add_address_to_hash(hash_val, &key->addr2);
342
343 hash_val += ( hash_val << 3 );
344 hash_val ^= ( hash_val >> 11 );
345 hash_val += ( hash_val << 15 );
346
347 return hash_val;
348 }
349
350 /*
351 * Compare two conversation keys, except for the port 2 value.
352 * We don't check both directions of the conversation - the routine
353 * doing the hash lookup has to do two searches, as the hash key
354 * will be different for the two directions.
355 */
356 static gint
conversation_match_no_port2(gconstpointer v,gconstpointer w)357 conversation_match_no_port2(gconstpointer v, gconstpointer w)
358 {
359 const conversation_key_t v1 = (const conversation_key_t)v;
360 const conversation_key_t v2 = (const conversation_key_t)w;
361
362 if (v1->etype != v2->etype)
363 return 0; /* different types of port */
364
365 /*
366 * Are the first and second port 1 values the same, the first and
367 * second address 1 values the same, and the first and second
368 * address 2 values the same?
369 */
370 if (v1->port1 == v2->port1 &&
371 addresses_equal(&v1->addr1, &v2->addr1) &&
372 addresses_equal(&v1->addr2, &v2->addr2)) {
373 /*
374 * Yes. It's the same conversation, and the two
375 * address/port pairs are going in the same direction.
376 */
377 return 1;
378 }
379
380 /*
381 * The addresses or the ports don't match.
382 */
383 return 0;
384 }
385
386 /*
387 * Compute the hash value for two given address/port pairs if the match
388 * has a wildcard address 2 and port 2.
389 */
390 static guint
conversation_hash_no_addr2_or_port2(gconstpointer v)391 conversation_hash_no_addr2_or_port2(gconstpointer v)
392 {
393 const conversation_key_t key = (const conversation_key_t)v;
394 guint hash_val;
395 address tmp_addr;
396
397 hash_val = 0;
398 tmp_addr.len = 4;
399
400 hash_val = add_address_to_hash(hash_val, &key->addr1);
401
402 tmp_addr.data = &key->port1;
403 hash_val = add_address_to_hash(hash_val, &tmp_addr);
404
405 hash_val += ( hash_val << 3 );
406 hash_val ^= ( hash_val >> 11 );
407 hash_val += ( hash_val << 15 );
408
409 return hash_val;
410 }
411
412 /*
413 * Compare the address 1 and port 1 in the two conversation keys.
414 * We don't check both directions of the conversation - the routine
415 * doing the hash lookup has to do two searches, as the hash key
416 * will be different for the two directions.
417 */
418 static gint
conversation_match_no_addr2_or_port2(gconstpointer v,gconstpointer w)419 conversation_match_no_addr2_or_port2(gconstpointer v, gconstpointer w)
420 {
421 const conversation_key_t v1 = (const conversation_key_t)v;
422 const conversation_key_t v2 = (const conversation_key_t)w;
423
424 if (v1->etype != v2->etype)
425 return 0; /* different types of port */
426
427 /*
428 * Are the first and second port 1 values the same and the first
429 * and second address 1 values the same?
430 */
431 if (v1->port1 == v2->port1 &&
432 addresses_equal(&v1->addr1, &v2->addr1)) {
433 /*
434 * Yes. It's the same conversation, and the two
435 * address/port pairs are going in the same direction.
436 */
437 return 1;
438 }
439
440 /*
441 * The addresses or the ports don't match.
442 */
443 return 0;
444 }
445
446 /**
447 * Create a new hash tables for conversations.
448 */
449 void
conversation_init(void)450 conversation_init(void)
451 {
452 /*
453 * Free up any space allocated for conversation protocol data
454 * areas.
455 *
456 * We can free the space, as the structures it contains are
457 * pointed to by conversation data structures that were freed
458 * above.
459 */
460 conversation_hashtable_exact =
461 wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), conversation_hash_exact,
462 conversation_match_exact);
463 conversation_hashtable_no_addr2 =
464 wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), conversation_hash_no_addr2,
465 conversation_match_no_addr2);
466 conversation_hashtable_no_port2 =
467 wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), conversation_hash_no_port2,
468 conversation_match_no_port2);
469 conversation_hashtable_no_addr2_or_port2 =
470 wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), conversation_hash_no_addr2_or_port2,
471 conversation_match_no_addr2_or_port2);
472
473 }
474
475 /**
476 * Initialize some variables every time a file is loaded or re-loaded.
477 */
conversation_epan_reset(void)478 void conversation_epan_reset(void)
479 {
480 /*
481 * Start the conversation indices over at 0.
482 */
483 new_index = 0;
484 }
485
486 /*
487 * Does the right thing when inserting into one of the conversation hash tables,
488 * taking into account ordering and hash chains and all that good stuff.
489 *
490 * Mostly adapted from the old conversation_new().
491 */
492 static void
conversation_insert_into_hashtable(wmem_map_t * hashtable,conversation_t * conv)493 conversation_insert_into_hashtable(wmem_map_t *hashtable, conversation_t *conv)
494 {
495 conversation_t *chain_head, *chain_tail, *cur, *prev;
496
497 chain_head = (conversation_t *)wmem_map_lookup(hashtable, conv->key_ptr);
498
499 if (NULL==chain_head) {
500 /* New entry */
501 conv->next = NULL;
502 conv->last = conv;
503 wmem_map_insert(hashtable, conv->key_ptr, conv);
504 DPRINT(("created a new conversation chain"));
505 }
506 else {
507 /* There's an existing chain for this key */
508 DPRINT(("there's an existing conversation chain"));
509
510 chain_tail = chain_head->last;
511
512 if (conv->setup_frame >= chain_tail->setup_frame) {
513 /* This convo belongs at the end of the chain */
514 conv->next = NULL;
515 conv->last = NULL;
516 chain_tail->next = conv;
517 chain_head->last = conv;
518 }
519 else {
520 /* Loop through the chain to find the right spot */
521 cur = chain_head;
522 prev = NULL;
523
524 for (; (conv->setup_frame > cur->setup_frame) && cur->next; prev=cur, cur=cur->next)
525 ;
526
527 if (NULL==prev) {
528 /* Changing the head of the chain */
529 conv->next = chain_head;
530 conv->last = chain_tail;
531 chain_head->last = NULL;
532 wmem_map_insert(hashtable, conv->key_ptr, conv);
533 }
534 else {
535 /* Inserting into the middle of the chain */
536 conv->next = cur;
537 conv->last = NULL;
538 prev->next = conv;
539 }
540 }
541 }
542 }
543
544 /*
545 * Does the right thing when removing from one of the conversation hash tables,
546 * taking into account ordering and hash chains and all that good stuff.
547 */
548 static void
conversation_remove_from_hashtable(wmem_map_t * hashtable,conversation_t * conv)549 conversation_remove_from_hashtable(wmem_map_t *hashtable, conversation_t *conv)
550 {
551 conversation_t *chain_head, *cur, *prev;
552
553 chain_head = (conversation_t *)wmem_map_lookup(hashtable, conv->key_ptr);
554
555 if (conv == chain_head) {
556 /* We are currently the front of the chain */
557 if (NULL == conv->next) {
558 /* We are the only conversation in the chain, no need to
559 * update next pointer, but do not call
560 * wmem_map_remove() either because the conv data
561 * will be re-inserted. */
562 wmem_map_steal(hashtable, conv->key_ptr);
563 }
564 else {
565 /* Update the head of the chain */
566 chain_head = conv->next;
567 chain_head->last = conv->last;
568
569 if (conv->latest_found == conv)
570 chain_head->latest_found = NULL;
571 else
572 chain_head->latest_found = conv->latest_found;
573
574 wmem_map_insert(hashtable, chain_head->key_ptr, chain_head);
575 }
576 }
577 else {
578 /* We are not the front of the chain. Loop through to find us.
579 * Start loop at chain_head->next rather than chain_head because
580 * we already know we're not at the head. */
581 cur = chain_head->next;
582 prev = chain_head;
583
584 for (; (cur != conv) && cur->next; prev=cur, cur=cur->next)
585 ;
586
587 if (cur != conv) {
588 /* XXX: Conversation not found. Wrong hashtable? */
589 return;
590 }
591
592 prev->next = conv->next;
593
594 if (NULL == conv->next) {
595 /* We're at the very end of the list. */
596 chain_head->last = prev;
597 }
598
599 if (chain_head->latest_found == conv)
600 chain_head->latest_found = prev;
601 }
602 }
603
604 /*
605 * Given two address/port pairs for a packet, create a new conversation
606 * to contain packets between those address/port pairs.
607 *
608 * The options field is used to specify whether the address 2 value
609 * and/or port 2 value are not given and any value is acceptable
610 * when searching for this conversation.
611 */
612 conversation_t *
conversation_new(const guint32 setup_frame,const address * addr1,const address * addr2,const endpoint_type etype,const guint32 port1,const guint32 port2,const guint options)613 conversation_new(const guint32 setup_frame, const address *addr1, const address *addr2,
614 const endpoint_type etype, const guint32 port1, const guint32 port2, const guint options)
615 {
616 /*
617 DISSECTOR_ASSERT(!(options | CONVERSATION_TEMPLATE) || ((options | (NO_ADDR2 | NO_PORT2 | NO_PORT2_FORCE))) &&
618 "A conversation template may not be constructed without wildcard options");
619 */
620 wmem_map_t* hashtable;
621 conversation_t *conversation=NULL;
622 conversation_key_t new_key;
623
624 #ifdef DEBUG_CONVERSATION
625 gchar *addr1_str, *addr2_str;
626 if (addr1 == NULL) {
627 /*
628 * No address 1.
629 */
630 if (options & NO_ADDR2) {
631 /*
632 * Neither address 1 nor address 2.
633 */
634 if (options & NO_PORT2) {
635 /*
636 * Port 1 but not port 2.
637 */
638 DPRINT(("creating conversation for frame #%u: ID %u (etype=%d)",
639 setup_frame, port1, etype));
640 } else {
641 /*
642 * Ports 1 and 2.
643 */
644 DPRINT(("creating conversation for frame #%u: %u -> %u (etype=%d)",
645 setup_frame, port1, port2, etype));
646 }
647 } else {
648 /*
649 * Address 2 but not address 1.
650 */
651 addr2_str = address_to_str(NULL, addr2);
652 if (options & NO_PORT2) {
653 /*
654 * Port 1 but not port 2.
655 */
656 DPRINT(("creating conversation for frame #%u: ID %u, address %s (etype=%d)",
657 setup_frame, port1, addr2_str, etype));
658 } else {
659 /*
660 * Ports 1 and 2.
661 */
662 DPRINT(("creating conversation for frame #%u: %u -> %s:%u (etype=%d)",
663 setup_frame, port1, addr2_str, port2, etype));
664 }
665 wmem_free(NULL, addr2_str);
666 }
667 } else {
668 /*
669 * Address 1.
670 */
671 addr1_str = address_to_str(NULL, addr1);
672 if (options & NO_ADDR2) {
673 /*
674 * Address 1 but no address 2.
675 */
676 if (options & NO_PORT2) {
677 /*
678 * Port 1 but not port 2.
679 */
680 DPRINT(("creating conversation for frame #%u: %s:%u (etype=%d)",
681 setup_frame, addr1_str, port1, etype));
682 } else {
683 /*
684 * Ports 1 and 2.
685 */
686 DPRINT(("creating conversation for frame #%u: %s:%u -> %u (etype=%d)",
687 setup_frame, addr1_str, port1, port2, etype));
688 }
689 } else {
690 /*
691 * Addresses 1 and 2.
692 */
693 addr2_str = address_to_str(NULL, addr2);
694 if (options & NO_PORT2) {
695 /*
696 * Port 1 but not port 2.
697 */
698 DPRINT(("creating conversation for frame #%u: %s:%u -> %s (etype=%d)",
699 setup_frame, addr1_str, port1, addr2_str, etype));
700 } else {
701 /*
702 * Ports 1 and 2.
703 */
704 DPRINT(("creating conversation for frame #%u: %s:%u -> %s:%u (etype=%d)",
705 setup_frame, addr1_str, port1, addr2_str, port2, etype));
706 }
707 wmem_free(NULL, addr2_str);
708 }
709 wmem_free(NULL, addr1_str);
710 }
711 #endif
712
713 if (options & NO_ADDR2) {
714 if (options & (NO_PORT2|NO_PORT2_FORCE)) {
715 hashtable = conversation_hashtable_no_addr2_or_port2;
716 } else {
717 hashtable = conversation_hashtable_no_addr2;
718 }
719 } else {
720 if (options & (NO_PORT2|NO_PORT2_FORCE)) {
721 hashtable = conversation_hashtable_no_port2;
722 } else {
723 hashtable = conversation_hashtable_exact;
724 }
725 }
726
727 new_key = wmem_new(wmem_file_scope(), struct conversation_key);
728 if (addr1 != NULL) {
729 copy_address_wmem(wmem_file_scope(), &new_key->addr1, addr1);
730 } else {
731 clear_address(&new_key->addr1);
732 }
733 if (addr2 != NULL) {
734 copy_address_wmem(wmem_file_scope(), &new_key->addr2, addr2);
735 } else {
736 clear_address(&new_key->addr2);
737 }
738 new_key->etype = etype;
739 new_key->port1 = port1;
740 new_key->port2 = port2;
741
742 conversation = wmem_new0(wmem_file_scope(), conversation_t);
743
744 conversation->conv_index = new_index;
745 conversation->setup_frame = conversation->last_frame = setup_frame;
746 conversation->data_list = NULL;
747
748 conversation->dissector_tree = wmem_tree_new(wmem_file_scope());
749
750 /* set the options and key pointer */
751 conversation->options = options;
752 conversation->key_ptr = new_key;
753
754 new_index++;
755
756 DINDENT();
757 conversation_insert_into_hashtable(hashtable, conversation);
758 DENDENT();
759
760 return conversation;
761 }
762
conversation_new_by_id(const guint32 setup_frame,const endpoint_type etype,const guint32 id,const guint options)763 conversation_t *conversation_new_by_id(const guint32 setup_frame, const endpoint_type etype, const guint32 id, const guint options)
764 {
765 /* Force the lack of an address or port 2 */
766 return conversation_new(setup_frame, NULL, NULL, etype, id, 0, options | NO_ADDR2 | NO_PORT2);
767 }
768
769 /*
770 * Set the port 2 value in a key. Remove the original from table,
771 * update the options and port values, insert the updated key.
772 */
773 void
conversation_set_port2(conversation_t * conv,const guint32 port)774 conversation_set_port2(conversation_t *conv, const guint32 port)
775 {
776 DISSECTOR_ASSERT_HINT(!(conv->options & CONVERSATION_TEMPLATE),
777 "Use the conversation_create_from_template function when the CONVERSATION_TEMPLATE bit is set in the options mask");
778
779 DPRINT(("called for port=%d", port));
780
781 /*
782 * If the port 2 value is not wildcarded, don't set it.
783 */
784 if ((!(conv->options & NO_PORT2)) || (conv->options & NO_PORT2_FORCE))
785 return;
786
787 DINDENT();
788 if (conv->options & NO_ADDR2) {
789 conversation_remove_from_hashtable(conversation_hashtable_no_addr2_or_port2, conv);
790 } else {
791 conversation_remove_from_hashtable(conversation_hashtable_no_port2, conv);
792 }
793 conv->options &= ~NO_PORT2;
794 conv->key_ptr->port2 = port;
795 if (conv->options & NO_ADDR2) {
796 conversation_insert_into_hashtable(conversation_hashtable_no_addr2, conv);
797 } else {
798 conversation_insert_into_hashtable(conversation_hashtable_exact, conv);
799 }
800 DENDENT();
801 }
802
803 /*
804 * Set the address 2 value in a key. Remove the original from
805 * table, update the options and port values, insert the updated key.
806 */
807 void
conversation_set_addr2(conversation_t * conv,const address * addr)808 conversation_set_addr2(conversation_t *conv, const address *addr)
809 {
810 char* addr_str;
811 DISSECTOR_ASSERT_HINT(!(conv->options & CONVERSATION_TEMPLATE),
812 "Use the conversation_create_from_template function when the CONVERSATION_TEMPLATE bit is set in the options mask");
813
814 addr_str = address_to_str(NULL, addr);
815 DPRINT(("called for addr=%s", addr_str));
816 wmem_free(NULL, addr_str);
817
818 /*
819 * If the address 2 value is not wildcarded, don't set it.
820 */
821 if (!(conv->options & NO_ADDR2))
822 return;
823
824 DINDENT();
825 if (conv->options & NO_PORT2) {
826 conversation_remove_from_hashtable(conversation_hashtable_no_addr2_or_port2, conv);
827 } else {
828 conversation_remove_from_hashtable(conversation_hashtable_no_port2, conv);
829 }
830 conv->options &= ~NO_ADDR2;
831 copy_address_wmem(wmem_file_scope(), &conv->key_ptr->addr2, addr);
832 if (conv->options & NO_PORT2) {
833 conversation_insert_into_hashtable(conversation_hashtable_no_port2, conv);
834 } else {
835 conversation_insert_into_hashtable(conversation_hashtable_exact, conv);
836 }
837 DENDENT();
838 }
839
840 /*
841 * Search a particular hash table for a conversation with the specified
842 * {addr1, port1, addr2, port2} and set up before frame_num.
843 */
844 static conversation_t *
conversation_lookup_hashtable(wmem_map_t * hashtable,const guint32 frame_num,const address * addr1,const address * addr2,const endpoint_type etype,const guint32 port1,const guint32 port2)845 conversation_lookup_hashtable(wmem_map_t *hashtable, const guint32 frame_num, const address *addr1, const address *addr2,
846 const endpoint_type etype, const guint32 port1, const guint32 port2)
847 {
848 conversation_t* convo=NULL;
849 conversation_t* match=NULL;
850 conversation_t* chain_head=NULL;
851 struct conversation_key key;
852
853 /*
854 * We don't make a copy of the address data, we just copy the
855 * pointer to it, as "key" disappears when we return.
856 */
857 if (addr1 != NULL) {
858 key.addr1 = *addr1;
859 } else {
860 clear_address(&key.addr1);
861 }
862 if (addr2 != NULL) {
863 key.addr2 = *addr2;
864 } else {
865 clear_address(&key.addr2);
866 }
867 key.etype = etype;
868 key.port1 = port1;
869 key.port2 = port2;
870
871 chain_head = (conversation_t *)wmem_map_lookup(hashtable, &key);
872
873 if (chain_head && (chain_head->setup_frame <= frame_num)) {
874 match = chain_head;
875
876 if ((chain_head->last)&&(chain_head->last->setup_frame<=frame_num))
877 return chain_head->last;
878
879 if ((chain_head->latest_found)&&(chain_head->latest_found->setup_frame<=frame_num))
880 match = chain_head->latest_found;
881
882 for (convo = match; convo && convo->setup_frame <= frame_num; convo = convo->next) {
883 if (convo->setup_frame > match->setup_frame) {
884 match = convo;
885 }
886 }
887 }
888
889 if (match)
890 chain_head->latest_found = match;
891
892 return match;
893 }
894
895
896 /*
897 * Given two address/port pairs for a packet, search for a conversation
898 * containing packets between those address/port pairs. Returns NULL if
899 * not found.
900 *
901 * We try to find the most exact match that we can, and then proceed to
902 * try wildcard matches on the "addr_b" and/or "port_b" argument if a more
903 * exact match failed.
904 *
905 * Either or both of the "addr_b" and "port_b" arguments may be specified as
906 * a wildcard by setting the NO_ADDR_B or NO_PORT_B flags in the "options"
907 * argument. We do only wildcard matches on addresses and ports specified
908 * as wildcards.
909 *
910 * I.e.:
911 *
912 * if neither "addr_b" nor "port_b" were specified as wildcards, we
913 * do an exact match (addr_a/port_a and addr_b/port_b) and, if that
914 * succeeds, we return a pointer to the matched conversation;
915 *
916 * otherwise, if "port_b" wasn't specified as a wildcard, we try to
917 * match any address 2 with the specified port 2 (addr_a/port_a and
918 * {any}/port_b) and, if that succeeds, we return a pointer to the
919 * matched conversation;
920 *
921 * otherwise, if "addr_b" wasn't specified as a wildcard, we try to
922 * match any port 2 with the specified address 2 (addr_a/port_a and
923 * addr_b/{any}) and, if that succeeds, we return a pointer to the
924 * matched conversation;
925 *
926 * otherwise, we try to match any address 2 and any port 2
927 * (addr_a/port_a and {any}/{any}) and, if that succeeds, we return
928 * a pointer to the matched conversation;
929 *
930 * otherwise, we found no matching conversation, and return NULL.
931 */
932 conversation_t *
find_conversation(const guint32 frame_num,const address * addr_a,const address * addr_b,const endpoint_type etype,const guint32 port_a,const guint32 port_b,const guint options)933 find_conversation(const guint32 frame_num, const address *addr_a, const address *addr_b, const endpoint_type etype,
934 const guint32 port_a, const guint32 port_b, const guint options)
935 {
936 conversation_t *conversation;
937
938 DINSTR(gchar *addr_a_str = address_to_str(NULL, addr_a));
939 DINSTR(gchar *addr_b_str = address_to_str(NULL, addr_b));
940 /*
941 * First try an exact match, if we have two addresses and ports.
942 */
943 if (!(options & (NO_ADDR_B|NO_PORT_B))) {
944 /*
945 * Neither search address B nor search port B are wildcarded,
946 * start out with an exact match.
947 */
948 DPRINT(("trying exact match: %s:%d -> %s:%d",
949 addr_a_str, port_a, addr_b_str, port_b));
950 conversation =
951 conversation_lookup_hashtable(conversation_hashtable_exact,
952 frame_num, addr_a, addr_b, etype,
953 port_a, port_b);
954 /* Didn't work, try the other direction */
955 if (conversation == NULL) {
956 DPRINT(("trying exact match: %s:%d -> %s:%d",
957 addr_b_str, port_b, addr_a_str, port_a));
958 conversation =
959 conversation_lookup_hashtable(conversation_hashtable_exact,
960 frame_num, addr_b, addr_a, etype,
961 port_b, port_a);
962 }
963 if ((conversation == NULL) && (addr_a->type == AT_FC)) {
964 /* In Fibre channel, OXID & RXID are never swapped as
965 * TCP/UDP ports are in TCP/IP.
966 */
967 DPRINT(("trying exact match: %s:%d -> %s:%d",
968 addr_b_str, port_a, addr_a_str, port_b));
969 conversation =
970 conversation_lookup_hashtable(conversation_hashtable_exact,
971 frame_num, addr_b, addr_a, etype,
972 port_a, port_b);
973 }
974 DPRINT(("exact match %sfound",conversation?"":"not "));
975 if (conversation != NULL)
976 goto end;
977 }
978
979 /*
980 * Well, that didn't find anything. Try matches that wildcard
981 * one of the addresses, if we have two ports.
982 */
983 if (!(options & NO_PORT_B)) {
984 /*
985 * Search port B isn't wildcarded.
986 *
987 * First try looking for a conversation with the specified
988 * address A and port A as the first address and port, and
989 * with any address and the specified port B as the second
990 * address and port.
991 * ("addr_b" doesn't take part in this lookup.)
992 */
993 DPRINT(("trying wildcarded match: %s:%d -> *:%d",
994 addr_a_str, port_a, port_b));
995 conversation =
996 conversation_lookup_hashtable(conversation_hashtable_no_addr2,
997 frame_num, addr_a, addr_b, etype, port_a, port_b);
998 if ((conversation == NULL) && (addr_a->type == AT_FC)) {
999 /* In Fibre channel, OXID & RXID are never swapped as
1000 * TCP/UDP ports are in TCP/IP.
1001 */
1002 DPRINT(("trying wildcarded match: %s:%d -> *:%d",
1003 addr_b_str, port_a, port_b));
1004 conversation =
1005 conversation_lookup_hashtable(conversation_hashtable_no_addr2,
1006 frame_num, addr_b, addr_a, etype,
1007 port_a, port_b);
1008 }
1009 if (conversation != NULL) {
1010 /*
1011 * If search address B isn't wildcarded, and this is for a
1012 * connection-oriented protocol, set the second address for this
1013 * conversation to address B, as that's the address that matched the
1014 * wildcarded second address for this conversation.
1015 *
1016 * (This assumes that, for all connection oriented protocols, the
1017 * endpoints of a connection have only one address each, i.e. you
1018 * don't get packets in a given direction coming from more than one
1019 * address, unless the CONVERSATION_TEMPLATE option is set.)
1020 */
1021 DPRINT(("wildcarded dest address match found"));
1022 if (!(conversation->options & NO_ADDR_B) && etype != ENDPOINT_UDP)
1023 {
1024 if (!(conversation->options & CONVERSATION_TEMPLATE))
1025 {
1026 conversation_set_addr2(conversation, addr_b);
1027 }
1028 else
1029 {
1030 conversation =
1031 conversation_create_from_template(conversation, addr_b, 0);
1032 }
1033 }
1034 goto end;
1035 }
1036
1037 /*
1038 * Well, that didn't find anything.
1039 * If search address B was specified, try looking for a
1040 * conversation with the specified address B and port B as
1041 * the first address and port, and with any address and the
1042 * specified port A as the second address and port (this
1043 * packet may be going in the opposite direction from the
1044 * first packet in the conversation).
1045 * ("addr_a" doesn't take part in this lookup.)
1046 */
1047 if (!(options & NO_ADDR_B)) {
1048 DPRINT(("trying wildcarded match: %s:%d -> *:%d",
1049 addr_b_str, port_b, port_a));
1050 conversation =
1051 conversation_lookup_hashtable(conversation_hashtable_no_addr2,
1052 frame_num, addr_b, addr_a, etype, port_b, port_a);
1053 if (conversation != NULL) {
1054 /*
1055 * If this is for a connection-oriented
1056 * protocol, set the second address for
1057 * this conversation to address A, as
1058 * that's the address that matched the
1059 * wildcarded second address for this
1060 * conversation.
1061 */
1062 DPRINT(("match found"));
1063 if (etype != ENDPOINT_UDP) {
1064 if (!(conversation->options & CONVERSATION_TEMPLATE))
1065 {
1066 conversation_set_addr2(conversation, addr_a);
1067 }
1068 else
1069 {
1070 conversation =
1071 conversation_create_from_template(conversation, addr_a, 0);
1072 }
1073 }
1074 goto end;
1075 }
1076 }
1077 }
1078
1079 /*
1080 * Well, that didn't find anything. Try matches that wildcard
1081 * one of the ports, if we have two addresses.
1082 */
1083 if (!(options & NO_ADDR_B)) {
1084 /*
1085 * Search address B isn't wildcarded.
1086 *
1087 * First try looking for a conversation with the specified
1088 * address A and port A as the first address and port, and
1089 * with the specified address B and any port as the second
1090 * address and port.
1091 * ("port_b" doesn't take part in this lookup.)
1092 */
1093 DPRINT(("trying wildcarded match: %s:%d -> %s:*",
1094 addr_a_str, port_a, addr_b_str));
1095 conversation =
1096 conversation_lookup_hashtable(conversation_hashtable_no_port2,
1097 frame_num, addr_a, addr_b, etype, port_a, port_b);
1098 if ((conversation == NULL) && (addr_a->type == AT_FC)) {
1099 /* In Fibre channel, OXID & RXID are never swapped as
1100 * TCP/UDP ports are in TCP/IP
1101 */
1102 DPRINT(("trying wildcarded match: %s:%d -> %s:*", addr_b_str, port_a, addr_a_str));
1103 conversation =
1104 conversation_lookup_hashtable(conversation_hashtable_no_port2,
1105 frame_num, addr_b, addr_a, etype, port_a, port_b);
1106 }
1107 if (conversation != NULL) {
1108 /*
1109 * If search port B isn't wildcarded, and this is for a connection-
1110 * oriented protocol, set the second port for this conversation to
1111 * port B, as that's the port that matched the wildcarded second port
1112 * for this conversation.
1113 *
1114 * (This assumes that, for all connection oriented protocols, the
1115 * endpoints of a connection have only one port each, i.e. you don't
1116 * get packets in a given direction coming from more than one port,
1117 * unless the CONVERSATION_TEMPLATE option is set.)
1118 */
1119 DPRINT(("match found"));
1120 if (!(conversation->options & NO_PORT_B) && etype != ENDPOINT_UDP)
1121 {
1122 if (!(conversation->options & CONVERSATION_TEMPLATE))
1123 {
1124 conversation_set_port2(conversation, port_b);
1125 }
1126 else
1127 {
1128 conversation =
1129 conversation_create_from_template(conversation, 0, port_b);
1130 }
1131 }
1132 goto end;
1133 }
1134
1135 /*
1136 * Well, that didn't find anything.
1137 * If search port B was specified, try looking for a
1138 * conversation with the specified address B and port B
1139 * as the first address and port, and with the specified
1140 * address A and any port as the second address and port
1141 * (this packet may be going in the opposite direction
1142 * from the first packet in the conversation).
1143 * ("port_a" doesn't take part in this lookup.)
1144 */
1145 if (!(options & NO_PORT_B)) {
1146 DPRINT(("trying wildcarded match: %s:%d -> %s:*",
1147 addr_b_str, port_b, addr_a_str));
1148 conversation =
1149 conversation_lookup_hashtable(conversation_hashtable_no_port2,
1150 frame_num, addr_b, addr_a, etype, port_b, port_a);
1151 if (conversation != NULL) {
1152 /*
1153 * If this is for a connection-oriented
1154 * protocol, set the second port for
1155 * this conversation to port A, as
1156 * that's the address that matched the
1157 * wildcarded second address for this
1158 * conversation.
1159 */
1160 DPRINT(("match found"));
1161 if (etype != ENDPOINT_UDP)
1162 {
1163 if (!(conversation->options & CONVERSATION_TEMPLATE))
1164 {
1165 conversation_set_port2(conversation, port_a);
1166 }
1167 else
1168 {
1169 conversation =
1170 conversation_create_from_template(conversation, 0, port_a);
1171 }
1172 }
1173 goto end;
1174 }
1175 }
1176 }
1177
1178 /*
1179 * Well, that didn't find anything. Try matches that wildcard
1180 * one address/port pair.
1181 *
1182 * First try looking for a conversation with the specified address A
1183 * and port A as the first address and port.
1184 * (Neither "addr_b" nor "port_b" take part in this lookup.)
1185 */
1186 DPRINT(("trying wildcarded match: %s:%d -> *:*", addr_a_str, port_a));
1187 conversation =
1188 conversation_lookup_hashtable(conversation_hashtable_no_addr2_or_port2,
1189 frame_num, addr_a, addr_b, etype, port_a, port_b);
1190 if (conversation != NULL) {
1191 /*
1192 * If this is for a connection-oriented protocol:
1193 *
1194 * if search address B isn't wildcarded, set the
1195 * second address for this conversation to address
1196 * B, as that's the address that matched the
1197 * wildcarded second address for this conversation;
1198 *
1199 * if search port B isn't wildcarded, set the
1200 * second port for this conversation to port B,
1201 * as that's the port that matched the wildcarded
1202 * second port for this conversation.
1203 */
1204 DPRINT(("match found"));
1205 if (etype != ENDPOINT_UDP)
1206 {
1207 if (!(conversation->options & CONVERSATION_TEMPLATE))
1208 {
1209 if (!(conversation->options & NO_ADDR_B))
1210 conversation_set_addr2(conversation, addr_b);
1211 if (!(conversation->options & NO_PORT_B))
1212 conversation_set_port2(conversation, port_b);
1213 }
1214 else
1215 {
1216 conversation =
1217 conversation_create_from_template(conversation, addr_b, port_b);
1218 }
1219 }
1220 goto end;
1221 }
1222 /* for Infiniband, don't try to look in addresses of reverse
1223 * direction, because it could be another different
1224 * valid conversation than what is being searched using
1225 * addr_a, port_a.
1226 */
1227 if (etype != ENDPOINT_IBQP)
1228 {
1229
1230 /*
1231 * Well, that didn't find anything.
1232 * If search address and port B were specified, try looking for a
1233 * conversation with the specified address B and port B as the
1234 * first address and port, and with any second address and port
1235 * (this packet may be going in the opposite direction from the
1236 * first packet in the conversation).
1237 * (Neither "addr_a" nor "port_a" take part in this lookup.)
1238 */
1239 if ((addr_a != NULL) && (addr_a->type == AT_FC)) {
1240 DPRINT(("trying wildcarded match: %s:%d -> *:*",
1241 addr_b_str, port_a));
1242 conversation =
1243 conversation_lookup_hashtable(conversation_hashtable_no_addr2_or_port2,
1244 frame_num, addr_b, addr_a, etype, port_a, port_b);
1245 } else {
1246 DPRINT(("trying wildcarded match: %s:%d -> *:*",
1247 addr_b_str, port_b));
1248 conversation =
1249 conversation_lookup_hashtable(conversation_hashtable_no_addr2_or_port2,
1250 frame_num, addr_b, addr_a, etype, port_b, port_a);
1251 }
1252 if (conversation != NULL) {
1253 /*
1254 * If this is for a connection-oriented protocol, set the
1255 * second address for this conversation to address A, as
1256 * that's the address that matched the wildcarded second
1257 * address for this conversation, and set the second port
1258 * for this conversation to port A, as that's the port
1259 * that matched the wildcarded second port for this
1260 * conversation.
1261 */
1262 DPRINT(("match found"));
1263 if (etype != ENDPOINT_UDP)
1264 {
1265 if (!(conversation->options & CONVERSATION_TEMPLATE))
1266 {
1267 conversation_set_addr2(conversation, addr_a);
1268 conversation_set_port2(conversation, port_a);
1269 }
1270 else
1271 {
1272 conversation = conversation_create_from_template(conversation, addr_a, port_a);
1273 }
1274 }
1275 goto end;
1276 }
1277 }
1278 DPRINT(("no matches found"));
1279
1280 /*
1281 * We found no conversation.
1282 */
1283 conversation = NULL;
1284
1285 end:
1286 DINSTR(wmem_free(NULL, addr_a_str));
1287 DINSTR(wmem_free(NULL, addr_b_str));
1288 return conversation;
1289 }
1290
find_conversation_by_id(const guint32 frame,const endpoint_type etype,const guint32 id,const guint options)1291 conversation_t *find_conversation_by_id(const guint32 frame, const endpoint_type etype, const guint32 id, const guint options)
1292 {
1293 /* Force the lack of a address or port B */
1294 return find_conversation(frame, &null_address_, &null_address_, etype, id, 0, options|NO_ADDR_B|NO_PORT_B);
1295 }
1296
1297 void
conversation_add_proto_data(conversation_t * conv,const int proto,void * proto_data)1298 conversation_add_proto_data(conversation_t *conv, const int proto, void *proto_data)
1299 {
1300 /* Add it to the list of items for this conversation. */
1301 if (conv->data_list == NULL)
1302 conv->data_list = wmem_tree_new(wmem_file_scope());
1303
1304 wmem_tree_insert32(conv->data_list, proto, proto_data);
1305 }
1306
1307 void *
conversation_get_proto_data(const conversation_t * conv,const int proto)1308 conversation_get_proto_data(const conversation_t *conv, const int proto)
1309 {
1310 /* No tree created yet */
1311 if (conv->data_list == NULL)
1312 return NULL;
1313
1314 return wmem_tree_lookup32(conv->data_list, proto);
1315 }
1316
1317 void
conversation_delete_proto_data(conversation_t * conv,const int proto)1318 conversation_delete_proto_data(conversation_t *conv, const int proto)
1319 {
1320 if (conv->data_list != NULL)
1321 wmem_tree_remove32(conv->data_list, proto);
1322 }
1323
1324 void
conversation_set_dissector_from_frame_number(conversation_t * conversation,const guint32 starting_frame_num,const dissector_handle_t handle)1325 conversation_set_dissector_from_frame_number(conversation_t *conversation,
1326 const guint32 starting_frame_num, const dissector_handle_t handle)
1327 {
1328 wmem_tree_insert32(conversation->dissector_tree, starting_frame_num, (void *)handle);
1329 }
1330
1331 void
conversation_set_dissector(conversation_t * conversation,const dissector_handle_t handle)1332 conversation_set_dissector(conversation_t *conversation, const dissector_handle_t handle)
1333 {
1334 conversation_set_dissector_from_frame_number(conversation, 0, handle);
1335 }
1336
1337 dissector_handle_t
conversation_get_dissector(conversation_t * conversation,const guint32 frame_num)1338 conversation_get_dissector(conversation_t *conversation, const guint32 frame_num)
1339 {
1340 return (dissector_handle_t)wmem_tree_lookup32_le(conversation->dissector_tree, frame_num);
1341 }
1342
try_conversation_call_dissector_helper(conversation_t * conversation,gboolean * dissector_success,tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data)1343 static gboolean try_conversation_call_dissector_helper(conversation_t *conversation, gboolean* dissector_success,
1344 tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
1345 {
1346 int ret;
1347 dissector_handle_t handle = (dissector_handle_t)wmem_tree_lookup32_le(
1348 conversation->dissector_tree, pinfo->num);
1349 if (handle == NULL)
1350 return FALSE;
1351
1352 ret = call_dissector_only(handle, tvb, pinfo, tree, data);
1353
1354 /* Let the caller decide what to do with success or rejection */
1355 (*dissector_success) = (ret != 0);
1356
1357 return TRUE;
1358 }
1359
1360 /*
1361 * Given two address/port pairs for a packet, search for a matching
1362 * conversation and, if found and it has a conversation dissector,
1363 * call that dissector and return TRUE, otherwise return FALSE.
1364 *
1365 * This helper uses call_dissector_only which will NOT call the default
1366 * "data" dissector if the packet was rejected.
1367 * Our caller is responsible to call the data dissector explicitly in case
1368 * this function returns FALSE.
1369 */
1370 gboolean
try_conversation_dissector(const address * addr_a,const address * addr_b,const endpoint_type etype,const guint32 port_a,const guint32 port_b,tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data,const guint options)1371 try_conversation_dissector(const address *addr_a, const address *addr_b, const endpoint_type etype,
1372 const guint32 port_a, const guint32 port_b, tvbuff_t *tvb, packet_info *pinfo,
1373 proto_tree *tree, void* data, const guint options)
1374 {
1375 conversation_t *conversation;
1376 gboolean dissector_success;
1377
1378 /* Try each mode based on option flags */
1379
1380 conversation = find_conversation(pinfo->num, addr_a, addr_b, etype, port_a, port_b, 0);
1381 if (conversation != NULL) {
1382 if (try_conversation_call_dissector_helper(conversation, &dissector_success, tvb, pinfo, tree, data))
1383 return dissector_success;
1384 }
1385
1386 if (options & NO_ADDR_B) {
1387 conversation = find_conversation(pinfo->num, addr_a, addr_b, etype, port_a, port_b, NO_ADDR_B);
1388 if (conversation != NULL) {
1389 if (try_conversation_call_dissector_helper(conversation, &dissector_success, tvb, pinfo, tree, data))
1390 return dissector_success;
1391 }
1392 }
1393
1394 if (options & NO_PORT_B) {
1395 conversation = find_conversation(pinfo->num, addr_a, addr_b, etype, port_a, port_b, NO_PORT_B);
1396 if (conversation != NULL) {
1397 if (try_conversation_call_dissector_helper(conversation, &dissector_success, tvb, pinfo, tree, data))
1398 return dissector_success;
1399 }
1400 }
1401
1402 if (options & (NO_ADDR_B|NO_PORT_B)) {
1403 conversation = find_conversation(pinfo->num, addr_a, addr_b, etype, port_a, port_b, NO_ADDR_B|NO_PORT_B);
1404 if (conversation != NULL) {
1405 if (try_conversation_call_dissector_helper(conversation, &dissector_success, tvb, pinfo, tree, data))
1406 return dissector_success;
1407 }
1408 }
1409
1410 return FALSE;
1411 }
1412
1413 gboolean
try_conversation_dissector_by_id(const endpoint_type etype,const guint32 id,tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data)1414 try_conversation_dissector_by_id(const endpoint_type etype, const guint32 id, tvbuff_t *tvb,
1415 packet_info *pinfo, proto_tree *tree, void* data)
1416 {
1417 conversation_t *conversation;
1418
1419 conversation = find_conversation_by_id(pinfo->num, etype, id, 0);
1420
1421 if (conversation != NULL) {
1422 int ret;
1423
1424 dissector_handle_t handle = (dissector_handle_t)wmem_tree_lookup32_le(conversation->dissector_tree, pinfo->num);
1425 if (handle == NULL)
1426 return FALSE;
1427 ret = call_dissector_only(handle, tvb, pinfo, tree, data);
1428 if (!ret) {
1429 /* this packet was rejected by the dissector
1430 * so return FALSE in case our caller wants
1431 * to do some cleaning up.
1432 */
1433 return FALSE;
1434 }
1435 return TRUE;
1436 }
1437 return FALSE;
1438 }
1439
1440 /** A helper function that calls find_conversation() using data from pinfo
1441 * The frame number and addresses are taken from pinfo.
1442 */
1443 conversation_t *
find_conversation_pinfo(packet_info * pinfo,const guint options)1444 find_conversation_pinfo(packet_info *pinfo, const guint options)
1445 {
1446 conversation_t *conv=NULL;
1447
1448 DINSTR(gchar *src_str = address_to_str(NULL, &pinfo->src));
1449 DINSTR(gchar *dst_str = address_to_str(NULL, &pinfo->dst));
1450 DPRINT(("called for frame #%u: %s:%d -> %s:%d (ptype=%d)",
1451 pinfo->num, src_str, pinfo->srcport,
1452 dst_str, pinfo->destport, pinfo->ptype));
1453 DINDENT();
1454 DINSTR(wmem_free(NULL, src_str));
1455 DINSTR(wmem_free(NULL, dst_str));
1456
1457 /* Have we seen this conversation before? */
1458 if (pinfo->use_endpoint) {
1459 DISSECTOR_ASSERT(pinfo->conv_endpoint);
1460 if ((conv = find_conversation(pinfo->num, &pinfo->conv_endpoint->addr1, &pinfo->conv_endpoint->addr2,
1461 pinfo->conv_endpoint->etype, pinfo->conv_endpoint->port1,
1462 pinfo->conv_endpoint->port2, pinfo->conv_endpoint->options)) != NULL) {
1463 DPRINT(("found previous conversation for frame #%u (last_frame=%d)",
1464 pinfo->num, conv->last_frame));
1465 if (pinfo->num > conv->last_frame) {
1466 conv->last_frame = pinfo->num;
1467 }
1468 }
1469 } else {
1470 if ((conv = find_conversation(pinfo->num, &pinfo->src, &pinfo->dst,
1471 conversation_pt_to_endpoint_type(pinfo->ptype), pinfo->srcport,
1472 pinfo->destport, options)) != NULL) {
1473 DPRINT(("found previous conversation for frame #%u (last_frame=%d)",
1474 pinfo->num, conv->last_frame));
1475 if (pinfo->num > conv->last_frame) {
1476 conv->last_frame = pinfo->num;
1477 }
1478 }
1479 }
1480
1481 DENDENT();
1482
1483 return conv;
1484 }
1485
1486 /* A helper function that calls find_conversation() and, if a conversation is
1487 * not found, calls conversation_new().
1488 * The frame number and addresses are taken from pinfo.
1489 * No options are used, though we could extend this API to include an options
1490 * parameter.
1491 */
1492 conversation_t *
find_or_create_conversation(packet_info * pinfo)1493 find_or_create_conversation(packet_info *pinfo)
1494 {
1495 conversation_t *conv=NULL;
1496
1497 /* Have we seen this conversation before? */
1498 if ((conv = find_conversation_pinfo(pinfo, 0)) == NULL) {
1499 /* No, this is a new conversation. */
1500 DPRINT(("did not find previous conversation for frame #%u",
1501 pinfo->num));
1502 DINDENT();
1503 conv = conversation_new(pinfo->num, &pinfo->src,
1504 &pinfo->dst, conversation_pt_to_endpoint_type(pinfo->ptype),
1505 pinfo->srcport, pinfo->destport, 0);
1506 DENDENT();
1507 }
1508
1509 return conv;
1510 }
1511
1512 conversation_t *
find_or_create_conversation_by_id(packet_info * pinfo,const endpoint_type etype,const guint32 id)1513 find_or_create_conversation_by_id(packet_info *pinfo, const endpoint_type etype, const guint32 id)
1514 {
1515 conversation_t *conv=NULL;
1516
1517 /* Have we seen this conversation before? */
1518 if ((conv = find_conversation_by_id(pinfo->num, etype, id, 0)) == NULL) {
1519 /* No, this is a new conversation. */
1520 DPRINT(("did not find previous conversation for frame #%u",
1521 pinfo->num));
1522 DINDENT();
1523 conv = conversation_new_by_id(pinfo->num, etype, id, 0);
1524 DENDENT();
1525 }
1526
1527 return conv;
1528 }
1529
conversation_create_endpoint(struct _packet_info * pinfo,address * addr1,address * addr2,endpoint_type etype,guint32 port1,guint32 port2,const guint options)1530 void conversation_create_endpoint(struct _packet_info *pinfo, address* addr1, address* addr2,
1531 endpoint_type etype, guint32 port1, guint32 port2, const guint options)
1532 {
1533 pinfo->conv_endpoint = wmem_new0(pinfo->pool, struct endpoint);
1534 pinfo->use_endpoint = TRUE;
1535
1536 if (addr1 != NULL)
1537 copy_address_wmem(pinfo->pool, &pinfo->conv_endpoint->addr1, addr1);
1538
1539 if (addr2 != NULL)
1540 copy_address_wmem(pinfo->pool, &pinfo->conv_endpoint->addr2, addr2);
1541
1542 pinfo->conv_endpoint->etype = etype;
1543 pinfo->conv_endpoint->port1 = port1;
1544 pinfo->conv_endpoint->port2 = port2;
1545 pinfo->conv_endpoint->options = options;
1546 }
1547
conversation_create_endpoint_by_id(struct _packet_info * pinfo,endpoint_type etype,guint32 id,const guint options)1548 void conversation_create_endpoint_by_id(struct _packet_info *pinfo,
1549 endpoint_type etype, guint32 id, const guint options)
1550 {
1551 /* Force the lack of a address or port B */
1552 conversation_create_endpoint(pinfo, &null_address_, &null_address_, etype, id, 0, options|NO_ADDR_B|NO_PORT_B);
1553 }
1554
conversation_get_endpoint_by_id(struct _packet_info * pinfo,endpoint_type etype,const guint options)1555 guint32 conversation_get_endpoint_by_id(struct _packet_info *pinfo, endpoint_type etype, const guint options)
1556 {
1557 if (pinfo->conv_endpoint == NULL)
1558 return 0;
1559
1560 if ((pinfo->conv_endpoint->etype != etype) &&
1561 ((options & USE_LAST_ENDPOINT) != USE_LAST_ENDPOINT))
1562 return 0;
1563
1564 return pinfo->conv_endpoint->port1;
1565 }
1566
1567 wmem_map_t *
get_conversation_hashtable_exact(void)1568 get_conversation_hashtable_exact(void)
1569 {
1570 return conversation_hashtable_exact;
1571 }
1572
1573 wmem_map_t *
get_conversation_hashtable_no_addr2(void)1574 get_conversation_hashtable_no_addr2(void)
1575 {
1576 return conversation_hashtable_no_addr2;
1577 }
1578
1579 wmem_map_t *
get_conversation_hashtable_no_port2(void)1580 get_conversation_hashtable_no_port2(void)
1581 {
1582 return conversation_hashtable_no_port2;
1583 }
1584
1585 wmem_map_t *
get_conversation_hashtable_no_addr2_or_port2(void)1586 get_conversation_hashtable_no_addr2_or_port2(void)
1587 {
1588 return conversation_hashtable_no_addr2_or_port2;
1589 }
1590
1591 address*
conversation_key_addr1(const conversation_key_t key)1592 conversation_key_addr1(const conversation_key_t key)
1593 {
1594 return &key->addr1;
1595 }
1596
1597 address*
conversation_key_addr2(const conversation_key_t key)1598 conversation_key_addr2(const conversation_key_t key)
1599 {
1600 return &key->addr2;
1601 }
1602
1603 guint32
conversation_key_port1(const conversation_key_t key)1604 conversation_key_port1(const conversation_key_t key)
1605 {
1606 return key->port1;
1607 }
1608
1609 guint32
conversation_key_port2(const conversation_key_t key)1610 conversation_key_port2(const conversation_key_t key)
1611 {
1612 return key->port2;
1613 }
1614
1615 WS_DLL_PUBLIC
conversation_pt_to_endpoint_type(port_type pt)1616 endpoint_type conversation_pt_to_endpoint_type(port_type pt)
1617 {
1618 switch (pt)
1619 {
1620 case PT_NONE:
1621 return ENDPOINT_NONE;
1622 case PT_SCTP:
1623 return ENDPOINT_SCTP;
1624 case PT_TCP:
1625 return ENDPOINT_TCP;
1626 case PT_UDP:
1627 return ENDPOINT_UDP;
1628 case PT_DCCP:
1629 return ENDPOINT_DCCP;
1630 case PT_IPX:
1631 return ENDPOINT_IPX;
1632 case PT_DDP:
1633 return ENDPOINT_DDP;
1634 case PT_IDP:
1635 return ENDPOINT_IDP;
1636 case PT_USB:
1637 return ENDPOINT_USB;
1638 case PT_I2C:
1639 return ENDPOINT_I2C;
1640 case PT_IBQP:
1641 return ENDPOINT_IBQP;
1642 case PT_BLUETOOTH:
1643 return ENDPOINT_BLUETOOTH;
1644 case PT_IWARP_MPA:
1645 return ENDPOINT_IWARP_MPA;
1646 }
1647
1648 DISSECTOR_ASSERT(FALSE);
1649 return ENDPOINT_NONE;
1650 }
1651
1652 gchar*
conversation_get_html_hash(const conversation_key_t key)1653 conversation_get_html_hash(const conversation_key_t key)
1654 {
1655 gchar *hash, *addr1, *addr2;
1656
1657 addr1 = address_to_str(NULL, &key->addr1);
1658 addr2 = address_to_str(NULL, &key->addr2);
1659 hash = wmem_strdup_printf(NULL, "<tr><td>%s</td><td>%d</td><td>%s</td><td>%d</td></tr>\n",
1660 addr1, key->port1, addr2, key->port2);
1661 wmem_free(NULL, addr1);
1662 wmem_free(NULL, addr2);
1663
1664 return hash;
1665 }
1666
1667 /*
1668 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1669 *
1670 * Local variables:
1671 * c-basic-offset: 8
1672 * tab-width: 8
1673 * indent-tabs-mode: t
1674 * End:
1675 *
1676 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1677 * :indentSize=8:tabSize=8:noTabs=false:
1678 */
1679