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