Add a new "prefs_register_protocol()" routine, which is like
[obnox/wireshark/wip.git] / packet-tcp.c
1 /* packet-tcp.c
2  * Routines for TCP packet disassembly
3  *
4  * $Id: packet-tcp.c,v 1.95 2001/01/03 07:53:43 guy Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@zing.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * 
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  * 
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #ifdef HAVE_SYS_TYPES_H
31 # include <sys/types.h>
32 #endif
33
34 #ifdef HAVE_NETINET_IN_H
35 # include <netinet/in.h>
36 #endif
37
38 #include <stdio.h>
39 #include <string.h>
40 #include <glib.h>
41 #include "in_cksum.h"
42
43 #ifdef NEED_SNPRINTF_H
44 # include "snprintf.h"
45 #endif
46
47 #include "globals.h"
48 #include "resolv.h"
49 #include "follow.h"
50 #include "prefs.h"
51 #include "plugins.h"
52 #include "packet-tcp.h"
53 #include "packet-ip.h"
54 #include "conversation.h"
55 #include "strutil.h"
56
57 /* Place TCP summary in proto tree */
58 static gboolean tcp_summary_in_tree = TRUE;
59
60 extern FILE* data_out_file;
61
62 guint16 tcp_urgent_pointer;
63
64 static int proto_tcp = -1;
65 static int hf_tcp_srcport = -1;
66 static int hf_tcp_dstport = -1;
67 static int hf_tcp_port = -1;
68 static int hf_tcp_seq = -1;
69 static int hf_tcp_nxtseq = -1;
70 static int hf_tcp_ack = -1;
71 static int hf_tcp_hdr_len = -1;
72 static int hf_tcp_flags = -1;
73 static int hf_tcp_flags_cwr = -1;
74 static int hf_tcp_flags_ecn = -1;
75 static int hf_tcp_flags_urg = -1;
76 static int hf_tcp_flags_ack = -1;
77 static int hf_tcp_flags_push = -1;
78 static int hf_tcp_flags_reset = -1;
79 static int hf_tcp_flags_syn = -1;
80 static int hf_tcp_flags_fin = -1;
81 static int hf_tcp_window_size = -1;
82 static int hf_tcp_checksum = -1;
83 static int hf_tcp_urgent_pointer = -1;
84
85 static gint ett_tcp = -1;
86 static gint ett_tcp_flags = -1;
87 static gint ett_tcp_options = -1;
88 static gint ett_tcp_option_sack = -1;
89
90 static dissector_table_t subdissector_table;
91 static heur_dissector_list_t heur_subdissector_list;
92
93 /* TCP Ports */
94
95 #define TCP_PORT_SMTP                   25
96
97 /* TCP structs and definitions */
98
99 typedef struct _e_tcphdr {
100   guint16 th_sport;
101   guint16 th_dport;
102   guint32 th_seq;
103   guint32 th_ack;
104   guint8  th_off_x2; /* combines th_off and th_x2 */
105   guint8  th_flags;
106 #define TH_FIN  0x01
107 #define TH_SYN  0x02
108 #define TH_RST  0x04
109 #define TH_PUSH 0x08
110 #define TH_ACK  0x10
111 #define TH_URG  0x20
112 #define TH_ECN  0x40
113 #define TH_CWR  0x80
114   guint16 th_win;
115   guint16 th_sum;
116   guint16 th_urp;
117 } e_tcphdr;
118
119 /*
120  *      TCP option
121  */
122  
123 #define TCPOPT_NOP              1       /* Padding */
124 #define TCPOPT_EOL              0       /* End of options */
125 #define TCPOPT_MSS              2       /* Segment size negotiating */
126 #define TCPOPT_WINDOW           3       /* Window scaling */
127 #define TCPOPT_SACK_PERM        4       /* SACK Permitted */
128 #define TCPOPT_SACK             5       /* SACK Block */
129 #define TCPOPT_ECHO             6
130 #define TCPOPT_ECHOREPLY        7
131 #define TCPOPT_TIMESTAMP        8       /* Better RTT estimations/PAWS */
132 #define TCPOPT_CC               11
133 #define TCPOPT_CCNEW            12
134 #define TCPOPT_CCECHO           13
135 #define TCPOPT_MD5              19      /* RFC2385 */
136
137 /*
138  *     TCP option lengths
139  */
140
141 #define TCPOLEN_MSS            4
142 #define TCPOLEN_WINDOW         3
143 #define TCPOLEN_SACK_PERM      2
144 #define TCPOLEN_SACK_MIN       2
145 #define TCPOLEN_ECHO           6
146 #define TCPOLEN_ECHOREPLY      6
147 #define TCPOLEN_TIMESTAMP      10
148 #define TCPOLEN_CC             6
149 #define TCPOLEN_CCNEW          6
150 #define TCPOLEN_CCECHO         6
151 #define TCPOLEN_MD5            18
152
153 static void
154 tcp_info_append_uint(frame_data *fd, const char *abbrev, guint32 val)
155 {
156   if (check_col(fd, COL_INFO))
157     col_append_fstr(fd, COL_INFO, " %s=%u", abbrev, val);
158 }
159
160 static void
161 dissect_tcpopt_maxseg(const ip_tcp_opt *optp, tvbuff_t *tvb,
162     int offset, guint optlen, frame_data *fd, proto_tree *opt_tree)
163 {
164   guint16 mss;
165
166   mss = tvb_get_ntohs(tvb, offset + 2);
167   proto_tree_add_text(opt_tree, tvb, offset,      optlen,
168                         "%s: %u bytes", optp->name, mss);
169   tcp_info_append_uint(fd, "MSS", mss);
170 }
171
172 static void
173 dissect_tcpopt_wscale(const ip_tcp_opt *optp, tvbuff_t *tvb,
174     int offset, guint optlen, frame_data *fd, proto_tree *opt_tree)
175 {
176   guint8 ws;
177
178   ws = tvb_get_guint8(tvb, offset + 2);
179   proto_tree_add_text(opt_tree, tvb, offset,      optlen,
180                         "%s: %u bytes", optp->name, ws);
181   tcp_info_append_uint(fd, "WS", ws);
182 }
183
184 static void
185 dissect_tcpopt_sack(const ip_tcp_opt *optp, tvbuff_t *tvb,
186     int offset, guint optlen, frame_data *fd, proto_tree *opt_tree)
187 {
188   proto_tree *field_tree = NULL;
189   proto_item *tf;
190   guint leftedge, rightedge;
191
192   tf = proto_tree_add_text(opt_tree, tvb, offset,      optlen, "%s:", optp->name);
193   offset += 2;  /* skip past type and length */
194   optlen -= 2;  /* subtract size of type and length */
195   while (optlen > 0) {
196     if (field_tree == NULL) {
197       /* Haven't yet made a subtree out of this option.  Do so. */
198       field_tree = proto_item_add_subtree(tf, *optp->subtree_index);
199     }
200     if (optlen < 4) {
201       proto_tree_add_text(field_tree, tvb, offset,      optlen,
202         "(suboption would go past end of option)");
203       break;
204     }
205     leftedge = tvb_get_ntohl(tvb, offset);
206     optlen -= 4;
207     if (optlen < 4) {
208       proto_tree_add_text(field_tree, tvb, offset,      optlen,
209         "(suboption would go past end of option)");
210       break;
211     }
212     /* XXX - check whether it goes past end of packet */
213     rightedge = tvb_get_ntohl(tvb, offset + 4);
214     optlen -= 4;
215     proto_tree_add_text(field_tree, tvb, offset,      8,
216         "left edge = %u, right edge = %u", leftedge, rightedge);
217     tcp_info_append_uint(fd, "SLE", leftedge);
218     tcp_info_append_uint(fd, "SRE", rightedge);
219     offset += 8;
220   }
221 }
222
223 static void
224 dissect_tcpopt_echo(const ip_tcp_opt *optp, tvbuff_t *tvb,
225     int offset, guint optlen, frame_data *fd, proto_tree *opt_tree)
226 {
227   guint32 echo;
228
229   echo = tvb_get_ntohl(tvb, offset + 2);
230   proto_tree_add_text(opt_tree, tvb, offset,      optlen,
231                         "%s: %u", optp->name, echo);
232   tcp_info_append_uint(fd, "ECHO", echo);
233 }
234
235 static void
236 dissect_tcpopt_timestamp(const ip_tcp_opt *optp, tvbuff_t *tvb,
237     int offset, guint optlen, frame_data *fd, proto_tree *opt_tree)
238 {
239   guint32 tsv, tser;
240
241   tsv = tvb_get_ntohl(tvb, offset + 2);
242   tser = tvb_get_ntohl(tvb, offset + 6);
243   proto_tree_add_text(opt_tree, tvb, offset,      optlen,
244     "%s: tsval %u, tsecr %u", optp->name, tsv, tser);
245   tcp_info_append_uint(fd, "TSV", tsv);
246   tcp_info_append_uint(fd, "TSER", tser);
247 }
248
249 static void
250 dissect_tcpopt_cc(const ip_tcp_opt *optp, tvbuff_t *tvb,
251     int offset, guint optlen, frame_data *fd, proto_tree *opt_tree)
252 {
253   guint32 cc;
254
255   cc = tvb_get_ntohl(tvb, offset + 2);
256   proto_tree_add_text(opt_tree, tvb, offset,      optlen,
257                         "%s: %u", optp->name, cc);
258   tcp_info_append_uint(fd, "CC", cc);
259 }
260
261 static const ip_tcp_opt tcpopts[] = {
262   {
263     TCPOPT_EOL,
264     "EOL",
265     NULL,
266     NO_LENGTH,
267     0,
268     NULL,
269   },
270   {
271     TCPOPT_NOP,
272     "NOP",
273     NULL,
274     NO_LENGTH,
275     0,
276     NULL,
277   },
278   {
279     TCPOPT_MSS,
280     "Maximum segment size",
281     NULL,
282     FIXED_LENGTH,
283     TCPOLEN_MSS,
284     dissect_tcpopt_maxseg
285   },
286   {
287     TCPOPT_WINDOW,
288     "Window scale",
289     NULL,
290     FIXED_LENGTH,
291     TCPOLEN_WINDOW,
292     dissect_tcpopt_wscale
293   },
294   {
295     TCPOPT_SACK_PERM,
296     "SACK permitted",
297     NULL,
298     FIXED_LENGTH,
299     TCPOLEN_SACK_PERM,
300     NULL,
301   },
302   {
303     TCPOPT_SACK,
304     "SACK",
305     &ett_tcp_option_sack,
306     VARIABLE_LENGTH,
307     TCPOLEN_SACK_MIN,
308     dissect_tcpopt_sack
309   },
310   {
311     TCPOPT_ECHO,
312     "Echo",
313     NULL,
314     FIXED_LENGTH,
315     TCPOLEN_ECHO,
316     dissect_tcpopt_echo
317   },
318   {
319     TCPOPT_ECHOREPLY,
320     "Echo reply",
321     NULL,
322     FIXED_LENGTH,
323     TCPOLEN_ECHOREPLY,
324     dissect_tcpopt_echo
325   },
326   {
327     TCPOPT_TIMESTAMP,
328     "Time stamp",
329     NULL,
330     FIXED_LENGTH,
331     TCPOLEN_TIMESTAMP,
332     dissect_tcpopt_timestamp
333   },
334   {
335     TCPOPT_CC,
336     "CC",
337     NULL,
338     FIXED_LENGTH,
339     TCPOLEN_CC,
340     dissect_tcpopt_cc
341   },
342   {
343     TCPOPT_CCNEW,
344     "CC.NEW",
345     NULL,
346     FIXED_LENGTH,
347     TCPOPT_CCNEW,
348     dissect_tcpopt_cc
349   },
350   {
351     TCPOPT_CCECHO,
352     "CC.ECHO",
353     NULL,
354     FIXED_LENGTH,
355     TCPOLEN_CCECHO,
356     dissect_tcpopt_cc
357   },
358   {
359     TCPOPT_MD5,
360     "TCP MD5 signature",
361     NULL,
362     FIXED_LENGTH,
363     TCPOLEN_MD5,
364     NULL
365   }
366 };
367
368 #define N_TCP_OPTS      (sizeof tcpopts / sizeof tcpopts[0])
369
370 /* TCP flags flag */
371 static const true_false_string flags_set_truth = {
372   "Set",
373   "Not set"
374 };
375
376
377 /* Determine if there is a sub-dissector and call it.  This has been */
378 /* separated into a stand alone routine to other protocol dissectors */
379 /* can call to it, ie. socks    */
380
381 void
382 decode_tcp_ports(tvbuff_t *tvb, int offset, packet_info *pinfo,
383         proto_tree *tree, int src_port, int dst_port)
384 {
385   tvbuff_t *next_tvb;
386 #ifdef HAVE_PLUGINS
387   const u_char *next_pd;
388   int next_offset;
389 #endif
390
391   next_tvb = tvb_new_subset(tvb, offset, -1, -1);
392
393 /* determine if this packet is part of a conversation and call dissector */
394 /* for the conversation if available */
395
396   if (try_conversation_dissector(&pinfo->src, &pinfo->dst, PT_TCP,
397                 src_port, dst_port, next_tvb, pinfo, tree))
398         return;
399
400   /* try to apply the plugins */
401 #ifdef HAVE_PLUGINS
402   {
403     plugin *pt_plug = plugin_list;
404
405     if (enabled_plugins_number > 0) {
406       tvb_compat(next_tvb, &next_pd, &next_offset);
407       while (pt_plug) {
408         if (pt_plug->enabled && strstr(pt_plug->protocol, "tcp") &&
409             tree && dfilter_apply(pt_plug->filter, tree, next_pd, pinfo->fd->cap_len)) {
410           pt_plug->dissector(next_pd, next_offset, pinfo->fd, tree);
411           return;
412         }
413         pt_plug = pt_plug->next;
414       }
415     }
416   }
417 #endif
418
419   /* do lookup with the subdissector table */
420   if (dissector_try_port(subdissector_table, src_port, next_tvb, pinfo, tree) ||
421       dissector_try_port(subdissector_table, dst_port, next_tvb, pinfo, tree))
422     return;
423
424   /* do lookup with the heuristic subdissector table */
425   if (dissector_try_heuristic(heur_subdissector_list, next_tvb, pinfo, tree))
426     return;
427
428   /* Oh, well, we don't know this; dissect it as data. */
429   dissect_data(next_tvb, 0, pinfo, tree);
430 }
431
432
433 static void
434 dissect_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
435 {
436   e_tcphdr   th;
437   proto_tree *tcp_tree = NULL, *field_tree = NULL;
438   proto_item *ti, *tf;
439   int        offset = 0;
440   gchar      flags[64] = "<None>";
441   gchar     *fstr[] = {"FIN", "SYN", "RST", "PSH", "ACK", "URG", "ECN", "CWR" };
442   gint       fpos = 0, i;
443   guint      bpos;
444   guint      hlen;
445   guint      optlen;
446   guint32    seglen;
447   guint32    nxtseq;
448   guint      len;
449   guint      reported_len;
450   vec_t      cksum_vec[4];
451   guint32    phdr[2];
452   guint16    computed_cksum;
453   guint      length_remaining;
454
455   CHECK_DISPLAY_AS_DATA(proto_tcp, tvb, pinfo, tree);
456
457   pinfo->current_proto = "TCP";
458
459   if (check_col(pinfo->fd, COL_PROTOCOL))
460     col_set_str(pinfo->fd, COL_PROTOCOL, "TCP");
461
462   /* Clear out the Info column. */
463   if (check_col(pinfo->fd, COL_INFO))
464     col_clear(pinfo->fd, COL_INFO);
465
466   /* Avoids alignment problems on many architectures. */
467   tvb_memcpy(tvb, (guint8 *)&th, offset, sizeof(e_tcphdr));
468   th.th_sport = ntohs(th.th_sport);
469   th.th_dport = ntohs(th.th_dport);
470   th.th_win   = ntohs(th.th_win);
471   th.th_sum   = ntohs(th.th_sum);
472   th.th_urp   = ntohs(th.th_urp);
473   th.th_seq   = ntohl(th.th_seq);
474   th.th_ack   = ntohl(th.th_ack);
475
476   /* Export the urgent pointer, for the benefit of protocols such as
477      rlogin. */
478   tcp_urgent_pointer = th.th_urp;
479  
480   if (check_col(pinfo->fd, COL_INFO) || tree) {  
481     for (i = 0; i < 8; i++) {
482       bpos = 1 << i;
483       if (th.th_flags & bpos) {
484         if (fpos) {
485           strcpy(&flags[fpos], ", ");
486           fpos += 2;
487         }
488         strcpy(&flags[fpos], fstr[i]);
489         fpos += 3;
490       }
491     }
492     flags[fpos] = '\0';
493   }
494   
495   hlen = hi_nibble(th.th_off_x2) * 4;  /* TCP header length, in bytes */
496
497   reported_len = tvb_reported_length(tvb);
498   len = tvb_length(tvb);
499
500   /* Compute the length of data in this segment. */
501   seglen = reported_len - hlen;
502
503   /* Compute the sequence number of next octet after this segment. */
504   nxtseq = th.th_seq + seglen;
505
506   if (check_col(pinfo->fd, COL_INFO)) {
507     if (th.th_flags & TH_URG)
508       col_append_fstr(pinfo->fd, COL_INFO, "%s > %s [%s] Seq=%u Ack=%u Win=%u Urg=%u Len=%d",
509         get_tcp_port(th.th_sport), get_tcp_port(th.th_dport), flags,
510         th.th_seq, th.th_ack, th.th_win, th.th_urp, seglen);
511     else
512       col_append_fstr(pinfo->fd, COL_INFO, "%s > %s [%s] Seq=%u Ack=%u Win=%u Len=%d",
513         get_tcp_port(th.th_sport), get_tcp_port(th.th_dport), flags,
514         th.th_seq, th.th_ack, th.th_win, seglen);
515   }
516   
517   if (tree) {
518     if (tcp_summary_in_tree) {
519             ti = proto_tree_add_protocol_format(tree, proto_tcp, tvb, offset, hlen, "Transmission Control Protocol, Src Port: %s (%u), Dst Port: %s (%u), Seq: %u, Ack: %u", get_tcp_port(th.th_sport), th.th_sport, get_tcp_port(th.th_dport), th.th_dport, th.th_seq, th.th_ack);
520     }
521     else {
522             ti = proto_tree_add_item(tree, proto_tcp, tvb, offset, hlen, FALSE);
523     }
524     tcp_tree = proto_item_add_subtree(ti, ett_tcp);
525     proto_tree_add_uint_format(tcp_tree, hf_tcp_srcport, tvb, offset, 2, th.th_sport,
526         "Source port: %s (%u)", get_tcp_port(th.th_sport), th.th_sport);
527     proto_tree_add_uint_format(tcp_tree, hf_tcp_dstport, tvb, offset + 2, 2, th.th_dport,
528         "Destination port: %s (%u)", get_tcp_port(th.th_dport), th.th_dport);
529     proto_tree_add_uint_hidden(tcp_tree, hf_tcp_port, tvb, offset, 2, th.th_sport);
530     proto_tree_add_uint_hidden(tcp_tree, hf_tcp_port, tvb, offset + 2, 2, th.th_dport);
531     proto_tree_add_uint(tcp_tree, hf_tcp_seq, tvb, offset + 4, 4, th.th_seq);
532     if (nxtseq != th.th_seq)
533       proto_tree_add_uint(tcp_tree, hf_tcp_nxtseq, tvb, offset, 0, nxtseq);
534     if (th.th_flags & TH_ACK)
535       proto_tree_add_uint(tcp_tree, hf_tcp_ack, tvb, offset + 8, 4, th.th_ack);
536     proto_tree_add_uint_format(tcp_tree, hf_tcp_hdr_len, tvb, offset + 12, 1, hlen,
537         "Header length: %u bytes", hlen);
538     tf = proto_tree_add_uint_format(tcp_tree, hf_tcp_flags, tvb, offset + 13, 1,
539         th.th_flags, "Flags: 0x%04x (%s)", th.th_flags, flags);
540     field_tree = proto_item_add_subtree(tf, ett_tcp_flags);
541     proto_tree_add_boolean(field_tree, hf_tcp_flags_cwr, tvb, offset + 13, 1, th.th_flags);
542     proto_tree_add_boolean(field_tree, hf_tcp_flags_ecn, tvb, offset + 13, 1, th.th_flags);
543     proto_tree_add_boolean(field_tree, hf_tcp_flags_urg, tvb, offset + 13, 1, th.th_flags);
544     proto_tree_add_boolean(field_tree, hf_tcp_flags_ack, tvb, offset + 13, 1, th.th_flags);
545     proto_tree_add_boolean(field_tree, hf_tcp_flags_push, tvb, offset + 13, 1, th.th_flags);
546     proto_tree_add_boolean(field_tree, hf_tcp_flags_reset, tvb, offset + 13, 1, th.th_flags);
547     proto_tree_add_boolean(field_tree, hf_tcp_flags_syn, tvb, offset + 13, 1, th.th_flags);
548     proto_tree_add_boolean(field_tree, hf_tcp_flags_fin, tvb, offset + 13, 1, th.th_flags);
549     proto_tree_add_uint(tcp_tree, hf_tcp_window_size, tvb, offset + 14, 2, th.th_win);
550     if (!pinfo->fragmented && len >= reported_len) {
551       /* The packet isn't part of a fragmented datagram and isn't
552          truncated, so we can checksum it.
553          XXX - make a bigger scatter-gather list once we do fragment
554          reassembly? */
555
556       /* Set up the fields of the pseudo-header. */
557       cksum_vec[0].ptr = pinfo->src.data;
558       cksum_vec[0].len = pinfo->src.len;
559       cksum_vec[1].ptr = pinfo->dst.data;
560       cksum_vec[1].len = pinfo->dst.len;
561       cksum_vec[2].ptr = (const guint8 *)&phdr;
562       switch (pinfo->src.type) {
563
564       case AT_IPv4:
565         phdr[0] = htonl((IP_PROTO_TCP<<16) + reported_len);
566         cksum_vec[2].len = 4;
567         break;
568
569       case AT_IPv6:
570         phdr[0] = htonl(reported_len);
571         phdr[1] = htonl(IP_PROTO_TCP);
572         cksum_vec[2].len = 8;
573         break;
574
575       default:
576         /* TCP runs only atop IPv4 and IPv6.... */
577         g_assert_not_reached();
578         break;
579       }
580       cksum_vec[3].ptr = tvb_get_ptr(tvb, offset, len);
581       cksum_vec[3].len = reported_len;
582       computed_cksum = in_cksum(&cksum_vec[0], 4);
583       if (computed_cksum == 0) {
584         proto_tree_add_uint_format(tcp_tree, hf_tcp_checksum, tvb,
585            offset + 16, 2, th.th_sum, "Checksum: 0x%04x (correct)", th.th_sum);
586       } else {
587         proto_tree_add_uint_format(tcp_tree, hf_tcp_checksum, tvb,
588            offset + 16, 2, th.th_sum,
589            "Checksum: 0x%04x (incorrect, should be 0x%04x)", th.th_sum,
590            in_cksum_shouldbe(th.th_sum, computed_cksum));
591       }
592     } else {
593       proto_tree_add_uint_format(tcp_tree, hf_tcp_checksum, tvb,
594        offset + 16, 2, th.th_sum, "Checksum: 0x%04x", th.th_sum);
595     }
596     if (th.th_flags & TH_URG)
597       proto_tree_add_uint(tcp_tree, hf_tcp_urgent_pointer, tvb, offset + 18, 2, th.th_urp);
598   }
599
600   /* Decode TCP options, if any. */
601   if (tree  && hlen > sizeof (e_tcphdr)) {
602     /* There's more than just the fixed-length header.  Decode the
603        options. */
604     optlen = hlen - sizeof (e_tcphdr); /* length of options, in bytes */
605     tf = proto_tree_add_text(tcp_tree, tvb, offset +  20, optlen,
606       "Options: (%d bytes)", optlen);
607     field_tree = proto_item_add_subtree(tf, ett_tcp_options);
608     dissect_ip_tcp_options(tvb, offset + 20, optlen,
609       tcpopts, N_TCP_OPTS, TCPOPT_EOL, pinfo->fd, field_tree);
610   }
611
612   /* Skip over header + options */
613   offset += hlen;
614
615   pinfo->ptype = PT_TCP;
616   pinfo->srcport = th.th_sport;
617   pinfo->destport = th.th_dport;
618   
619   /* Check the packet length to see if there's more data
620      (it could be an ACK-only packet) */
621   length_remaining = tvb_length_remaining(tvb, offset);
622   if (length_remaining != 0) {
623     if (th.th_flags & TH_RST) {
624       /*
625        * RFC1122 says:
626        *
627        *        4.2.2.12  RST Segment: RFC-793 Section 3.4
628        *
629        *          A TCP SHOULD allow a received RST segment to include data.
630        *
631        *          DISCUSSION
632        *               It has been suggested that a RST segment could contain
633        *               ASCII text that encoded and explained the cause of the
634        *               RST.  No standard has yet been established for such
635        *               data.
636        *
637        * so for segments with RST we just display the data as text.
638        */
639       proto_tree_add_text(tcp_tree, tvb, offset, length_remaining,
640                             "Reset cause: %s",
641                             tvb_format_text(tvb, offset, length_remaining));
642     } else
643       decode_tcp_ports( tvb, offset, pinfo, tree, th.th_sport, th.th_dport);
644   }
645  
646   if( data_out_file ) {
647     reassemble_tcp( th.th_seq,          /* sequence number */
648         seglen,                         /* data length */
649         tvb_get_ptr(tvb, offset, length_remaining),     /* data */
650         length_remaining,               /* captured data length */
651         ( th.th_flags & TH_SYN ),       /* is syn set? */
652         &pinfo->net_src,
653         &pinfo->net_dst,
654         pinfo->srcport,
655         pinfo->destport);
656   }
657 }
658
659 void
660 proto_register_tcp(void)
661 {
662         static hf_register_info hf[] = {
663
664                 { &hf_tcp_srcport,
665                 { "Source Port",                "tcp.srcport", FT_UINT16, BASE_DEC, NULL, 0x0,
666                         "" }},
667
668                 { &hf_tcp_dstport,
669                 { "Destination Port",           "tcp.dstport", FT_UINT16, BASE_DEC, NULL, 0x0,
670                         "" }},
671
672                 { &hf_tcp_port,
673                 { "Source or Destination Port", "tcp.port", FT_UINT16, BASE_DEC, NULL, 0x0,
674                         "" }},
675
676                 { &hf_tcp_seq,
677                 { "Sequence number",            "tcp.seq", FT_UINT32, BASE_DEC, NULL, 0x0,
678                         "" }},
679
680                 { &hf_tcp_nxtseq,
681                 { "Next sequence number",       "tcp.nxtseq", FT_UINT32, BASE_DEC, NULL, 0x0,
682                         "" }},
683
684                 { &hf_tcp_ack,
685                 { "Acknowledgement number",     "tcp.ack", FT_UINT32, BASE_DEC, NULL, 0x0,
686                         "" }},
687
688                 { &hf_tcp_hdr_len,
689                 { "Header Length",              "tcp.hdr_len", FT_UINT8, BASE_DEC, NULL, 0x0,
690                         "" }},
691
692                 { &hf_tcp_flags,
693                 { "Flags",                      "tcp.flags", FT_UINT8, BASE_HEX, NULL, 0x0,
694                         "" }},
695
696                 { &hf_tcp_flags_cwr,
697                 { "Congestion Window Reduced (CWR)",                    "tcp.flags.cwr", FT_BOOLEAN, 8, TFS(&flags_set_truth), TH_CWR,
698                         "" }},
699
700                 { &hf_tcp_flags_ecn,
701                 { "ECN-Echo",                   "tcp.flags.ecn", FT_BOOLEAN, 8, TFS(&flags_set_truth), TH_ECN,
702                         "" }},
703
704                 { &hf_tcp_flags_urg,
705                 { "Urgent",                     "tcp.flags.urg", FT_BOOLEAN, 8, TFS(&flags_set_truth), TH_URG,
706                         "" }},
707
708                 { &hf_tcp_flags_ack,
709                 { "Acknowledgment",             "tcp.flags.ack", FT_BOOLEAN, 8, TFS(&flags_set_truth), TH_ACK,
710                         "" }},
711
712                 { &hf_tcp_flags_push,
713                 { "Push",                       "tcp.flags.push", FT_BOOLEAN, 8, TFS(&flags_set_truth), TH_PUSH,
714                         "" }},
715
716                 { &hf_tcp_flags_reset,
717                 { "Reset",                      "tcp.flags.reset", FT_BOOLEAN, 8, TFS(&flags_set_truth), TH_RST,
718                         "" }},
719
720                 { &hf_tcp_flags_syn,
721                 { "Syn",                        "tcp.flags.syn", FT_BOOLEAN, 8, TFS(&flags_set_truth), TH_SYN,
722                         "" }},
723
724                 { &hf_tcp_flags_fin,
725                 { "Fin",                        "tcp.flags.fin", FT_BOOLEAN, 8, TFS(&flags_set_truth), TH_FIN,
726                         "" }},
727
728                 { &hf_tcp_window_size,
729                 { "Window size",                "tcp.window_size", FT_UINT16, BASE_DEC, NULL, 0x0,
730                         "" }},
731
732                 { &hf_tcp_checksum,
733                 { "Checksum",                   "tcp.checksum", FT_UINT16, BASE_HEX, NULL, 0x0,
734                         "" }},
735
736                 { &hf_tcp_urgent_pointer,
737                 { "Urgent pointer",             "tcp.urgent_pointer", FT_UINT16, BASE_DEC, NULL, 0x0,
738                         "" }},
739         };
740         static gint *ett[] = {
741                 &ett_tcp,
742                 &ett_tcp_flags,
743                 &ett_tcp_options,
744                 &ett_tcp_option_sack,
745         };
746         module_t *tcp_module;
747
748         proto_tcp = proto_register_protocol("Transmission Control Protocol",
749             "TCP", "tcp");
750         proto_register_field_array(proto_tcp, hf, array_length(hf));
751         proto_register_subtree_array(ett, array_length(ett));
752
753         /* subdissector code */
754         subdissector_table = register_dissector_table("tcp.port");
755         register_heur_dissector_list("tcp", &heur_subdissector_list);
756
757         /* Register configuration preferences */
758         tcp_module = prefs_register_protocol(proto_tcp, NULL);
759         prefs_register_bool_preference(tcp_module, "tcp_summary_in_tree",
760             "Show TCP summary in protocol tree",
761 "Whether the TCP summary line should be shown in the protocol tree",
762             &tcp_summary_in_tree);
763 }
764
765 void
766 proto_reg_handoff_tcp(void)
767 {
768         dissector_add("ip.proto", IP_PROTO_TCP, dissect_tcp);
769 }