changed numbers to bullets and removed nbp dissector item - in progress
[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.51 1999/12/07 06:10:00 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 <glib.h>
40 #include "packet.h"
41 #include "resolv.h"
42 #include "follow.h"
43 #include "util.h"
44
45 #ifdef NEED_SNPRINTF_H
46 # ifdef HAVE_STDARG_H
47 #  include <stdarg.h>
48 # else
49 #  include <varargs.h>
50 # endif
51 # include "snprintf.h"
52 #endif
53
54 #ifndef __PACKET_IP_H__
55 #include "packet-ip.h"
56 #endif
57
58 extern FILE* data_out_file;
59
60 static gchar info_str[COL_MAX_LEN];
61 static int   info_len;
62
63 static int proto_tcp = -1;
64 static int hf_tcp_srcport = -1;
65 static int hf_tcp_dstport = -1;
66 static int hf_tcp_port = -1;
67 static int hf_tcp_seq = -1;
68 static int hf_tcp_ack = -1;
69 static int hf_tcp_hdr_len = -1;
70 static int hf_tcp_flags = -1;
71 static int hf_tcp_flags_urg = -1;
72 static int hf_tcp_flags_ack = -1;
73 static int hf_tcp_flags_push = -1;
74 static int hf_tcp_flags_reset = -1;
75 static int hf_tcp_flags_syn = -1;
76 static int hf_tcp_flags_fin = -1;
77 static int hf_tcp_window_size = -1;
78 static int hf_tcp_checksum = -1;
79 static int hf_tcp_urgent_pointer = -1;
80
81 static gint ett_tcp = -1;
82 static gint ett_tcp_flags = -1;
83 static gint ett_tcp_options = -1;
84 static gint ett_tcp_option_sack = -1;
85
86 /* TCP Ports */
87
88 #define TCP_PORT_FTPDATA  20
89 #define TCP_PORT_FTP      21
90 #define TCP_PORT_TELNET   23
91 #define TCP_PORT_SMTP     25
92 #define TCP_PORT_HTTP     80
93 #define TCP_PORT_TACACS   49
94 #define TCP_PORT_POP      110
95 #define TCP_PORT_NNTP     119
96 #define TCP_PORT_NTP      123
97 #define TCP_PORT_NBSS     139
98 #define TCP_PORT_IMAP     143
99 #define TCP_PORT_BGP      179
100 #define TCP_PORT_SRVLOC   427
101 #define TCP_PORT_PRINTER  515
102 #define TCP_PORT_NCP      524
103 #define TCP_ALT_PORT_HTTP 8080
104 #define TCP_PORT_PPTP     1723
105 #define TCP_PORT_RTSP     554
106 #define TCP_PORT_YHOO     5050
107 #define TCP_PORT_MAPI     1065
108 #define TCP_PORT_TNS      1521
109 #define TCP_PORT_IRC      6667 /* good candidate for dynamic port specification */
110
111 /* TCP structs and definitions */
112
113 typedef struct _e_tcphdr {
114   guint16 th_sport;
115   guint16 th_dport;
116   guint32 th_seq;
117   guint32 th_ack;
118   guint8  th_off_x2; /* combines th_off and th_x2 */
119   guint8  th_flags;
120 #define TH_FIN  0x01
121 #define TH_SYN  0x02
122 #define TH_RST  0x04
123 #define TH_PUSH 0x08
124 #define TH_ACK  0x10
125 #define TH_URG  0x20
126   guint16 th_win;
127   guint16 th_sum;
128   guint16 th_urp;
129 } e_tcphdr;
130
131 /*
132  *      TCP option
133  */
134  
135 #define TCPOPT_NOP              1       /* Padding */
136 #define TCPOPT_EOL              0       /* End of options */
137 #define TCPOPT_MSS              2       /* Segment size negotiating */
138 #define TCPOPT_WINDOW           3       /* Window scaling */
139 #define TCPOPT_SACK_PERM        4       /* SACK Permitted */
140 #define TCPOPT_SACK             5       /* SACK Block */
141 #define TCPOPT_ECHO             6
142 #define TCPOPT_ECHOREPLY        7
143 #define TCPOPT_TIMESTAMP        8       /* Better RTT estimations/PAWS */
144 #define TCPOPT_CC               11
145 #define TCPOPT_CCNEW            12
146 #define TCPOPT_CCECHO           13
147
148 /*
149  *     TCP option lengths
150  */
151
152 #define TCPOLEN_MSS            4
153 #define TCPOLEN_WINDOW         3
154 #define TCPOLEN_SACK_PERM      2
155 #define TCPOLEN_SACK_MIN       2
156 #define TCPOLEN_ECHO           6
157 #define TCPOLEN_ECHOREPLY      6
158 #define TCPOLEN_TIMESTAMP      10
159 #define TCPOLEN_CC             6
160 #define TCPOLEN_CCNEW          6
161 #define TCPOLEN_CCECHO         6
162
163 static void
164 tcp_info_append_uint(const char *abbrev, guint32 val) {
165   int add_len = 0;
166   
167   if (info_len > 0)
168   if(info_len > 0)
169     add_len = snprintf(&info_str[info_len], COL_MAX_LEN - info_len, " %s=%u",
170       abbrev, val);
171   if (add_len > 0)
172     info_len += add_len;
173 }
174
175 static void
176 dissect_tcpopt_maxseg(const ip_tcp_opt *optp, const u_char *opd,
177     int offset, guint optlen, proto_tree *opt_tree)
178 {
179   proto_tree_add_text(opt_tree, offset,      optlen,
180                         "%s: %u bytes", optp->name, pntohs(opd));
181   tcp_info_append_uint("MSS", pntohs(opd));
182 }
183
184 static void
185 dissect_tcpopt_wscale(const ip_tcp_opt *optp, const u_char *opd,
186     int offset, guint optlen, proto_tree *opt_tree)
187 {
188   proto_tree_add_text(opt_tree, offset,      optlen,
189                         "%s: %u bytes", optp->name, *opd);
190   tcp_info_append_uint("WS", *opd);
191 }
192
193 static void
194 dissect_tcpopt_sack(const ip_tcp_opt *optp, const u_char *opd,
195     int offset, guint optlen, proto_tree *opt_tree)
196 {
197   proto_tree *field_tree = NULL;
198   proto_item *tf;
199   guint leftedge, rightedge;
200
201   tf = proto_tree_add_text(opt_tree, offset,      optlen, "%s:", optp->name);
202   offset += 2;  /* skip past type and length */
203   optlen -= 2;  /* subtract size of type and length */
204   while (optlen > 0) {
205     if (field_tree == NULL) {
206       /* Haven't yet made a subtree out of this option.  Do so. */
207       field_tree = proto_item_add_subtree(tf, *optp->subtree_index);
208     }
209     if (optlen < 4) {
210       proto_tree_add_text(field_tree, offset,      optlen,
211         "(suboption would go past end of option)");
212       break;
213     }
214     /* XXX - check whether it goes past end of packet */
215     leftedge = pntohl(opd);
216     opd += 4;
217     optlen -= 4;
218     if (optlen < 4) {
219       proto_tree_add_text(field_tree, offset,      optlen,
220         "(suboption would go past end of option)");
221       break;
222     }
223     /* XXX - check whether it goes past end of packet */
224     rightedge = pntohl(opd);
225     opd += 4;
226     optlen -= 4;
227     proto_tree_add_text(field_tree, offset,      8,
228         "left edge = %u, right edge = %u", leftedge, rightedge);
229     tcp_info_append_uint("SLE", leftedge);
230     tcp_info_append_uint("SRE", rightedge);
231     offset += 8;
232   }
233 }
234
235 static void
236 dissect_tcpopt_echo(const ip_tcp_opt *optp, const u_char *opd,
237     int offset, guint optlen, proto_tree *opt_tree)
238 {
239   proto_tree_add_text(opt_tree, offset,      optlen,
240                         "%s: %u", optp->name, pntohl(opd));
241   tcp_info_append_uint("ECHO", pntohl(opd));
242 }
243
244 static void
245 dissect_tcpopt_timestamp(const ip_tcp_opt *optp, const u_char *opd,
246     int offset, guint optlen, proto_tree *opt_tree)
247 {
248   proto_tree_add_text(opt_tree, offset,      optlen,
249     "%s: tsval %u, tsecr %u", optp->name, pntohl(opd), pntohl(opd + 4));
250   tcp_info_append_uint("TSV", pntohl(opd));
251   tcp_info_append_uint("TSER", pntohl(opd + 4));
252 }
253
254 static void
255 dissect_tcpopt_cc(const ip_tcp_opt *optp, const u_char *opd,
256     int offset, guint optlen, proto_tree *opt_tree)
257 {
258   proto_tree_add_text(opt_tree, offset,      optlen,
259                         "%s: %u", optp->name, pntohl(opd));
260   tcp_info_append_uint("CC", pntohl(opd));
261 }
262
263 static const ip_tcp_opt tcpopts[] = {
264   {
265     TCPOPT_EOL,
266     "EOL",
267     NULL,
268     NO_LENGTH,
269     0,
270     NULL,
271   },
272   {
273     TCPOPT_NOP,
274     "NOP",
275     NULL,
276     NO_LENGTH,
277     0,
278     NULL,
279   },
280   {
281     TCPOPT_MSS,
282     "Maximum segment size",
283     NULL,
284     FIXED_LENGTH,
285     TCPOLEN_MSS,
286     dissect_tcpopt_maxseg
287   },
288   {
289     TCPOPT_WINDOW,
290     "Window scale",
291     NULL,
292     FIXED_LENGTH,
293     TCPOLEN_WINDOW,
294     dissect_tcpopt_wscale
295   },
296   {
297     TCPOPT_SACK_PERM,
298     "SACK permitted",
299     NULL,
300     FIXED_LENGTH,
301     TCPOLEN_SACK_PERM,
302     NULL,
303   },
304   {
305     TCPOPT_SACK,
306     "SACK",
307     &ett_tcp_option_sack,
308     VARIABLE_LENGTH,
309     TCPOLEN_SACK_MIN,
310     dissect_tcpopt_sack
311   },
312   {
313     TCPOPT_ECHO,
314     "Echo",
315     NULL,
316     FIXED_LENGTH,
317     TCPOLEN_ECHO,
318     dissect_tcpopt_echo
319   },
320   {
321     TCPOPT_ECHOREPLY,
322     "Echo reply",
323     NULL,
324     FIXED_LENGTH,
325     TCPOLEN_ECHOREPLY,
326     dissect_tcpopt_echo
327   },
328   {
329     TCPOPT_TIMESTAMP,
330     "Time stamp",
331     NULL,
332     FIXED_LENGTH,
333     TCPOLEN_TIMESTAMP,
334     dissect_tcpopt_timestamp
335   },
336   {
337     TCPOPT_CC,
338     "CC",
339     NULL,
340     FIXED_LENGTH,
341     TCPOLEN_CC,
342     dissect_tcpopt_cc
343   },
344   {
345     TCPOPT_CCNEW,
346     "CC.NEW",
347     NULL,
348     FIXED_LENGTH,
349     TCPOPT_CCNEW,
350     dissect_tcpopt_cc
351   },
352   {
353     TCPOPT_CCECHO,
354     "CC.ECHO",
355     NULL,
356     FIXED_LENGTH,
357     TCPOLEN_CCECHO,
358     dissect_tcpopt_cc
359   }
360 };
361
362 #define N_TCP_OPTS      (sizeof tcpopts / sizeof tcpopts[0])
363
364 /* TCP flags flag */
365 static const true_false_string flags_set_truth = {
366   "Set",
367   "Not set"
368 };
369
370 void
371 dissect_tcp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
372   e_tcphdr   th;
373   proto_tree *tcp_tree = NULL, *field_tree = NULL;
374   proto_item *ti, *tf;
375   gchar      flags[64] = "<None>";
376   gchar     *fstr[] = {"FIN", "SYN", "RST", "PSH", "ACK", "URG"};
377   gint       fpos = 0, i;
378   guint      bpos;
379   guint      hlen;
380   guint      optlen;
381   guint      packet_max = pi.len;
382
383   /* To do: Check for {cap len,pkt len} < struct len */
384   /* Avoids alignment problems on many architectures. */
385   memcpy(&th, &pd[offset], sizeof(e_tcphdr));
386   th.th_sport = ntohs(th.th_sport);
387   th.th_dport = ntohs(th.th_dport);
388   th.th_win   = ntohs(th.th_win);
389   th.th_sum   = ntohs(th.th_sum);
390   th.th_urp   = ntohs(th.th_urp);
391   th.th_seq   = ntohl(th.th_seq);
392   th.th_ack   = ntohl(th.th_ack);
393   
394   info_len = 0;
395
396   if (check_col(fd, COL_PROTOCOL) || tree) {  
397     for (i = 0; i < 6; i++) {
398       bpos = 1 << i;
399       if (th.th_flags & bpos) {
400         if (fpos) {
401           strcpy(&flags[fpos], ", ");
402           fpos += 2;
403         }
404         strcpy(&flags[fpos], fstr[i]);
405         fpos += 3;
406       }
407     }
408     flags[fpos] = '\0';
409   }
410   
411   hlen = hi_nibble(th.th_off_x2) * 4;  /* TCP header length, in bytes */
412
413   if (check_col(fd, COL_PROTOCOL))
414     col_add_str(fd, COL_PROTOCOL, "TCP");
415   if (check_col(fd, COL_INFO)) {
416     /* Copy the data into info_str in case one of the option handling
417        routines needs to append to it. */
418     if (th.th_flags & TH_URG)
419       info_len = snprintf(info_str, COL_MAX_LEN, "%s > %s [%s] Seq=%u Ack=%u Win=%u Urg=%u",
420         get_tcp_port(th.th_sport), get_tcp_port(th.th_dport), flags,
421         th.th_seq, th.th_ack, th.th_win, th.th_urp);
422     else
423       info_len = snprintf(info_str, COL_MAX_LEN, "%s > %s [%s] Seq=%u Ack=%u Win=%u",
424         get_tcp_port(th.th_sport), get_tcp_port(th.th_dport), flags,
425         th.th_seq, th.th_ack, th.th_win);
426     /* The info column is actually written after the options are decoded */
427   }
428   
429   if (tree) {
430     ti = proto_tree_add_item_format(tree, proto_tcp, offset, hlen, NULL, "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);
431     tcp_tree = proto_item_add_subtree(ti, ett_tcp);
432     proto_tree_add_item_format(tcp_tree, hf_tcp_srcport, offset, 2, th.th_sport,
433         "Source port: %s (%u)", get_tcp_port(th.th_sport), th.th_sport);
434     proto_tree_add_item_format(tcp_tree, hf_tcp_dstport, offset + 2, 2, th.th_dport,
435         "Destination port: %s (%u)", get_tcp_port(th.th_dport), th.th_dport);
436     proto_tree_add_item_hidden(tcp_tree, hf_tcp_port, offset, 2, th.th_sport);
437     proto_tree_add_item_hidden(tcp_tree, hf_tcp_port, offset + 2, 2, th.th_dport);
438     proto_tree_add_item(tcp_tree, hf_tcp_seq, offset + 4, 4, th.th_seq);
439     if (th.th_flags & TH_ACK)
440       proto_tree_add_item(tcp_tree, hf_tcp_ack, offset + 8, 4, th.th_ack);
441     proto_tree_add_item_format(tcp_tree, hf_tcp_hdr_len, offset + 12, 1, hlen,
442         "Header length: %u bytes", hlen);
443     tf = proto_tree_add_item_format(tcp_tree, hf_tcp_flags, offset + 13, 1,
444         th.th_flags, "Flags: 0x%04x (%s)", th.th_flags, flags);
445     field_tree = proto_item_add_subtree(tf, ett_tcp_flags);
446     proto_tree_add_item(field_tree, hf_tcp_flags_urg, offset + 13, 1, th.th_flags);
447     proto_tree_add_item(field_tree, hf_tcp_flags_ack, offset + 13, 1, th.th_flags);
448     proto_tree_add_item(field_tree, hf_tcp_flags_push, offset + 13, 1, th.th_flags);
449     proto_tree_add_item(field_tree, hf_tcp_flags_reset, offset + 13, 1, th.th_flags);
450     proto_tree_add_item(field_tree, hf_tcp_flags_syn, offset + 13, 1, th.th_flags);
451     proto_tree_add_item(field_tree, hf_tcp_flags_fin, offset + 13, 1, th.th_flags);
452     proto_tree_add_item(tcp_tree, hf_tcp_window_size, offset + 14, 2, th.th_win);
453     proto_tree_add_item(tcp_tree, hf_tcp_checksum, offset + 16, 2, th.th_sum);
454     if (th.th_flags & TH_URG)
455       proto_tree_add_item(tcp_tree, hf_tcp_urgent_pointer, offset + 18, 2, th.th_urp);
456   }
457
458   /* Decode TCP options, if any. */
459   if (tree  && hlen > sizeof (e_tcphdr)) {
460     /* There's more than just the fixed-length header.  Decode the
461        options. */
462     optlen = hlen - sizeof (e_tcphdr); /* length of options, in bytes */
463     tf = proto_tree_add_text(tcp_tree, offset +  20, optlen,
464       "Options: (%d bytes)", optlen);
465     field_tree = proto_item_add_subtree(tf, ett_tcp_options);
466     dissect_ip_tcp_options(&pd[offset + 20], offset + 20, optlen,
467       tcpopts, N_TCP_OPTS, TCPOPT_EOL, field_tree);
468   }
469
470   if (check_col(fd, COL_INFO))
471     col_add_str(fd, COL_INFO, info_str);
472
473   /* Skip over header + options */
474   offset += hlen;
475
476   pi.ptype = PT_TCP;
477   pi.srcport = th.th_sport;
478   pi.destport = th.th_dport;
479   
480   /* Check the packet length to see if there's more data
481      (it could be an ACK-only packet) */
482   if (packet_max > offset) {
483
484     /* ONC RPC.  We can't base this on anything in the TCP header; we have
485        to look at the payload.  If "dissect_rpc()" returns TRUE, it was
486        an RPC packet, otherwise it's some other type of packet. */
487     if (dissect_rpc(pd, offset, fd, tree))
488       goto reas;
489
490     /* XXX - this should be handled the way UDP handles this, with a table
491        of port numbers to which stuff can be added */
492 #define PORT_IS(port)   (th.th_sport == port || th.th_dport == port)
493     if (PORT_IS(TCP_PORT_PRINTER))
494       dissect_lpd(pd, offset, fd, tree);
495     else if (PORT_IS(TCP_PORT_TELNET)) {
496       pi.match_port = TCP_PORT_TELNET;
497       dissect_telnet(pd, offset, fd, tree);
498     } else if (PORT_IS(TCP_PORT_FTPDATA)) {
499       pi.match_port = TCP_PORT_FTPDATA;
500       dissect_ftpdata(pd, offset, fd, tree);
501     } else if (PORT_IS(TCP_PORT_FTP)) {
502       pi.match_port = TCP_PORT_FTP;
503       dissect_ftp(pd, offset, fd, tree);
504     } else if (PORT_IS(TCP_PORT_POP)) {
505       pi.match_port = TCP_PORT_POP;
506       dissect_pop(pd, offset, fd, tree);
507     } else if (PORT_IS(TCP_PORT_IMAP)) {
508       pi.match_port = TCP_PORT_IMAP;
509       dissect_imap(pd, offset, fd, tree);
510     } else if (PORT_IS(TCP_PORT_NNTP)) {
511       pi.match_port = TCP_PORT_NNTP;
512       dissect_nntp(pd, offset, fd, tree);
513     } else if (PORT_IS(TCP_PORT_NTP)) {
514       pi.match_port = TCP_PORT_NTP;
515       dissect_ntp(pd, offset, fd, tree);
516     } else if (PORT_IS(TCP_PORT_PPTP)) {
517       pi.match_port = TCP_PORT_PPTP;
518       dissect_pptp(pd, offset, fd, tree);
519     } else if (PORT_IS(TCP_PORT_HTTP) || PORT_IS(TCP_ALT_PORT_HTTP)
520             || PORT_IS(631))
521       dissect_http(pd, offset, fd, tree);
522     else if (PORT_IS(TCP_PORT_NBSS)) {
523       pi.match_port = TCP_PORT_NBSS;
524       dissect_nbss(pd, offset, fd, tree);
525     } else if (PORT_IS(TCP_PORT_RTSP))
526       dissect_rtsp(pd, offset, fd, tree);
527     else if (PORT_IS(TCP_PORT_BGP)) {
528       pi.match_port = TCP_PORT_BGP;
529       dissect_bgp(pd, offset, fd, tree);
530     } else if (PORT_IS(TCP_PORT_TACACS)) {
531       pi.match_port = TCP_PORT_TACACS;
532       dissect_tacplus(pd, offset, fd, tree);
533     } else if (PORT_IS(TCP_PORT_MAPI)) {
534       pi.match_port = TCP_PORT_MAPI;
535       dissect_mapi(pd, offset, fd, tree);
536     } else if (PORT_IS(TCP_PORT_TNS)) {
537       pi.match_port = TCP_PORT_TNS;
538       dissect_tns(pd, offset, fd, tree);
539     } else if (PORT_IS(TCP_PORT_IRC)) {
540       pi.match_port = TCP_PORT_IRC;
541       dissect_irc(pd, offset, fd, tree);
542     } else if (PORT_IS(TCP_PORT_SRVLOC)) {
543       pi.match_port = TCP_PORT_SRVLOC;
544       dissect_srvloc(pd, offset, fd, tree);
545     } else if (PORT_IS(TCP_PORT_NCP)) {
546       pi.match_port = TCP_PORT_NCP;
547       dissect_ncp(pd, offset, fd, tree);
548     } else {
549         /* check existence of high level protocols */
550
551         if (memcmp(&pd[offset], "GIOP",  4) == 0) {
552           dissect_giop(pd, offset, fd, tree);
553         }
554         else if ( PORT_IS(TCP_PORT_YHOO) && 
555                 (memcmp(&pd[offset], "YPNS",  4) == 0 ||
556                         memcmp(&pd[offset], "YHOO",  4) == 0 )) {
557           dissect_yhoo(pd, offset, fd, tree);
558         }
559         else {
560           dissect_data(pd, offset, fd, tree);
561         }
562     }
563   }
564
565 reas:
566  
567   if( data_out_file ) {
568     reassemble_tcp( th.th_seq,          /* sequence number */
569         ( pi.len - offset ),            /* data length */
570         ( pd+offset ),                  /* data */
571         ( pi.captured_len - offset ),   /* captured data length */
572         ( th.th_flags & TH_SYN ),       /* is syn set? */
573         &pi.net_src,
574         &pi.net_dst,
575         pi.srcport,
576         pi.destport,
577         fd->rel_secs,
578         fd->rel_usecs);
579   }
580 }
581
582 void
583 proto_register_tcp(void)
584 {
585         static hf_register_info hf[] = {
586
587                 { &hf_tcp_srcport,
588                 { "Source Port",                "tcp.srcport", FT_UINT16, BASE_DEC, NULL, 0x0,
589                         "" }},
590
591                 { &hf_tcp_dstport,
592                 { "Destination Port",           "tcp.dstport", FT_UINT16, BASE_DEC, NULL, 0x0,
593                         "" }},
594
595                 { &hf_tcp_port,
596                 { "Source or Destination Port", "tcp.port", FT_UINT16, BASE_DEC, NULL, 0x0,
597                         "" }},
598
599                 { &hf_tcp_seq,
600                 { "Sequence number",            "tcp.seq", FT_UINT32, BASE_DEC, NULL, 0x0,
601                         "" }},
602
603                 { &hf_tcp_ack,
604                 { "Acknowledgement number",     "tcp.ack", FT_UINT32, BASE_DEC, NULL, 0x0,
605                         "" }},
606
607                 { &hf_tcp_hdr_len,
608                 { "Header Length",              "tcp.hdr_len", FT_UINT8, BASE_DEC, NULL, 0x0,
609                         "" }},
610
611                 { &hf_tcp_flags,
612                 { "Flags",                      "tcp.flags", FT_UINT8, BASE_HEX, NULL, 0x0,
613                         "" }},
614
615                 { &hf_tcp_flags_urg,
616                 { "Urgent",                     "tcp.flags.urg", FT_BOOLEAN, 8, TFS(&flags_set_truth), TH_URG,
617                         "" }},
618
619                 { &hf_tcp_flags_ack,
620                 { "Acknowledgment",             "tcp.flags.ack", FT_BOOLEAN, 8, TFS(&flags_set_truth), TH_ACK,
621                         "" }},
622
623                 { &hf_tcp_flags_push,
624                 { "Push",                       "tcp.flags.push", FT_BOOLEAN, 8, TFS(&flags_set_truth), TH_PUSH,
625                         "" }},
626
627                 { &hf_tcp_flags_reset,
628                 { "Reset",                      "tcp.flags.reset", FT_BOOLEAN, 8, TFS(&flags_set_truth), TH_RST,
629                         "" }},
630
631                 { &hf_tcp_flags_syn,
632                 { "Syn",                        "tcp.flags.syn", FT_BOOLEAN, 8, TFS(&flags_set_truth), TH_SYN,
633                         "" }},
634
635                 { &hf_tcp_flags_fin,
636                 { "Fin",                        "tcp.flags.fin", FT_BOOLEAN, 8, TFS(&flags_set_truth), TH_FIN,
637                         "" }},
638
639                 { &hf_tcp_window_size,
640                 { "Window size",                "tcp.window_size", FT_UINT16, BASE_DEC, NULL, 0x0,
641                         "" }},
642
643                 { &hf_tcp_checksum,
644                 { "Checksum",                   "tcp.checksum", FT_UINT16, BASE_HEX, NULL, 0x0,
645                         "" }},
646
647                 { &hf_tcp_urgent_pointer,
648                 { "Urgent pointer",             "tcp.urgent_pointer", FT_UINT16, BASE_DEC, NULL, 0x0,
649                         "" }},
650         };
651         static gint *ett[] = {
652                 &ett_tcp,
653                 &ett_tcp_flags,
654                 &ett_tcp_options,
655                 &ett_tcp_option_sack,
656         };
657
658         proto_tcp = proto_register_protocol ("Transmission Control Protocol", "tcp");
659         proto_register_field_array(proto_tcp, hf, array_length(hf));
660         proto_register_subtree_array(ett, array_length(ett));
661 }