1 /*
2  * Copyright (c) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
3  *               2002, 2003, 2004
4  *	Ohio University.
5  *
6  * ---
7  *
8  * Starting with the release of tcptrace version 6 in 2001, tcptrace
9  * is licensed under the GNU General Public License (GPL).  We believe
10  * that, among the available licenses, the GPL will do the best job of
11  * allowing tcptrace to continue to be a valuable, freely-available
12  * and well-maintained tool for the networking community.
13  *
14  * Previous versions of tcptrace were released under a license that
15  * was much less restrictive with respect to how tcptrace could be
16  * used in commercial products.  Because of this, I am willing to
17  * consider alternate license arrangements as allowed in Section 10 of
18  * the GNU GPL.  Before I would consider licensing tcptrace under an
19  * alternate agreement with a particular individual or company,
20  * however, I would have to be convinced that such an alternative
21  * would be to the greater benefit of the networking community.
22  *
23  * ---
24  *
25  * This file is part of Tcptrace.
26  *
27  * Tcptrace was originally written and continues to be maintained by
28  * Shawn Ostermann with the help of a group of devoted students and
29  * users (see the file 'THANKS').  The work on tcptrace has been made
30  * possible over the years through the generous support of NASA GRC,
31  * the National Science Foundation, and Sun Microsystems.
32  *
33  * Tcptrace is free software; you can redistribute it and/or modify it
34  * under the terms of the GNU General Public License as published by
35  * the Free Software Foundation; either version 2 of the License, or
36  * (at your option) any later version.
37  *
38  * Tcptrace is distributed in the hope that it will be useful, but
39  * WITHOUT ANY WARRANTY; without even the implied warranty of
40  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
41  * General Public License for more details.
42  *
43  * You should have received a copy of the GNU General Public License
44  * along with Tcptrace (in the file 'COPYING'); if not, write to the
45  * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
46  * MA 02111-1307 USA
47  *
48  * Author:	Shawn Ostermann
49  * 		School of Electrical Engineering and Computer Science
50  * 		Ohio University
51  * 		Athens, OH
52  *		ostermann@cs.ohiou.edu
53  *		http://www.tcptrace.org/
54  */
55 #include "tcptrace.h"
56 static char const GCC_UNUSED copyright[] =
57     "@(#)Copyright (c) 2004 -- Ohio University.\n";
58 static char const GCC_UNUSED rcsid[] =
59     "@(#)$Header$";
60 
61 
62 #include "gcache.h"
63 
64 
65 /* locally global variables */
66 static int tcp_packet_count = 0;
67 static int search_count = 0;
68 static int active_conn_count = 0;
69 static int closed_conn_count = 0;
70 static Bool *ignore_pairs = NULL;/* which ones will we ignore */
71 static Bool bottom_letters = 0;	/* I don't use this anymore */
72 static Bool more_conns_ignored = FALSE;
73 static double sample_elapsed_time=0; /* to keep track of owin samples */
74 static double total_elapsed_time=0; /* to keep track of owin samples */
75 static int num_removed_tcp_pairs = 0;
76 static int tline_left  = 0; /* left and right time lines for the time line charts */
77 static int tline_right = 0;
78 
79 /* provided globals  */
80 int num_tcp_pairs = -1;	/* how many pairs we've allocated */
81 tcp_pair **ttp = NULL;	/* array of pointers to allocated pairs */
82 int max_tcp_pairs = 64; /* initial value, automatically increases */
83 u_long tcp_trace_count = 0;
84 
85 
86 /* local routine definitions */
87 static tcp_pair *NewTTP(struct ip *, struct tcphdr *);
88 static tcp_pair *FindTTP(struct ip *, struct tcphdr *, int *, ptp_ptr **);
89 static void MoreTcpPairs(int num_needed);
90 static void ExtractContents(u_long seq, u_long tcp_data_bytes,
91 			    u_long saved_data_bytes, void *pdata, tcb *ptcb);
92 static Bool check_hw_dups(u_short id, seqnum seq, tcb *ptcb);
93 static u_long SeqRep(tcb *ptcb, u_long seq);
94 static void UpdateConnLists(ptp_ptr *tcp_ptr, struct tcphdr *ptcp);
95 static void UpdateConnList(ptp_ptr *tcp_ptr,
96 			   const Bool valid,
97 			   ptp_ptr **conn_list_head,
98 			   ptp_ptr **conn_list_tail);
99 static void RemoveOldConns(ptp_ptr **conn_list_head,
100 			   ptp_ptr **conn_list_tail,
101 			   const unsigned expire_interval,
102 			   const Bool num_conn_check,
103 			   int *conn_count);
104 static void RemoveConn(const ptp_ptr *tcp_ptr);
105 static void RemoveTcpPair(const ptp_ptr *tcp_ptr);
106 static Bool MissingData(tcp_pair *ptp);
107 
108 /* options */
109 Bool show_zero_window = TRUE;
110 Bool show_rexmit = TRUE;
111 Bool show_out_order = TRUE;
112 Bool show_sacks = TRUE;
113 Bool show_rtt_dongles = FALSE;
114 Bool show_triple_dupack = TRUE;
115 Bool show_zwnd_probes = TRUE;
116 Bool nonames = FALSE;
117 Bool use_short_names = FALSE;
118 Bool show_urg = TRUE;
119 int thru_interval = 10;	/* in segments */
120 
121 
122 /* what colors to use */
123 /* choose from: "green" "red" "blue" "yellow" "purple" "orange"
124    "magenta" "pink" */
125 char *window_color	= "yellow";
126 char *ack_color		= "green";
127 char *sack_color	= "purple";
128 char *data_color	= "white";
129 char *retrans_color	= "red";
130 char *hw_dup_color	= "blue";
131 char *out_order_color	= "pink";
132 char *text_color	= "magenta";
133 char *default_color	= "white";
134 char *synfin_color	= "orange";
135 char *push_color	= "white";	/* top arrow for PUSHed segments */
136 char *ecn_color		= "yellow";
137 char *urg_color		= "red";
138 char *probe_color       = "orange";
139 char *a2b_seg_color     = "green";     /* colors for segments on the time line chart */
140 char *b2a_seg_color     = "yellow";
141 
142 
143 /* ack diamond dongle colors */
144 char *ackdongle_nosample_color	= "blue";
145 char *ackdongle_ambig_color	= "red";
146 
147 
148 
149 /*
150  * ipcopyaddr: copy an IPv4 or IPv6 address
151  */
IP_COPYADDR(ipaddr * ptoaddr,ipaddr * pfromaddr)152 static inline void IP_COPYADDR (ipaddr *ptoaddr, ipaddr *pfromaddr)
153 {
154     if (ADDR_ISV6(pfromaddr)) {
155 	memcpy(ptoaddr->un.ip6.s6_addr, pfromaddr->un.ip6.s6_addr, 16);
156 	ptoaddr->addr_vers = 6;
157     } else {
158 	ptoaddr->un.ip4.s_addr = pfromaddr->un.ip4.s_addr;
159 	ptoaddr->addr_vers = 4;
160     }
161 }
162 
163 
164 
165 /*
166  * ipsameaddr: test for equality of two IPv4 or IPv6 addresses
167  */
IP_SAMEADDR(ipaddr * paddr1,ipaddr * paddr2)168 static inline int IP_SAMEADDR (ipaddr *paddr1, ipaddr *paddr2)
169 {
170     int ret = 0;
171     if (ADDR_ISV4(paddr1)) {
172 	if (ADDR_ISV4(paddr2))
173 	    ret = (paddr1->un.ip4.s_addr == paddr2->un.ip4.s_addr);
174     } else {
175 	/* already know ADDR_ISV6(paddr1) */
176 	if (ADDR_ISV6(paddr2))
177 	    ret = (memcmp(paddr1->un.ip6.s6_addr,
178 			  paddr2->un.ip6.s6_addr,16) == 0);
179     }
180     if (debug > 3)
181 	printf("SameAddr(%s(%d),%s(%d)) returns %d\n",
182 	       HostName(*paddr1), ADDR_VERSION(paddr1),
183 	       HostName(*paddr2), ADDR_VERSION(paddr2),
184 	       ret);
185     return ret;
186 }
187 
188 /*
189  *  iplowaddr: test if one IPv4 or IPv6 address is lower than the second one
190  */
IP_LOWADDR(ipaddr * paddr1,ipaddr * paddr2)191 static inline int IP_LOWADDR (ipaddr *paddr1, ipaddr *paddr2)
192 {
193     int ret = 0;
194     if (ADDR_ISV6(paddr1)) {
195 	if (ADDR_ISV6(paddr2))
196 	    ret = (memcmp(paddr1->un.ip6.s6_addr,
197 			  paddr2->un.ip6.s6_addr,16) < 0);
198     } else {
199 	/* already know ADDR_ISV4(paddr1) */
200 	if (ADDR_ISV4(paddr2))
201 	    ret = (paddr1->un.ip4.s_addr < paddr2->un.ip4.s_addr);
202     }
203     if (debug > 3)
204 	printf("LowAddr(%s(%d),%s(%d)) returns %d\n",
205 	       HostName(*paddr1), ADDR_VERSION(paddr1),
206 	       HostName(*paddr2), ADDR_VERSION(paddr2),
207 	       ret);
208     return ret;
209 }
210 
211 
212 /* return elapsed time in microseconds */
213 /* (time2 - time1) */
214 double
elapsed(struct timeval time1,struct timeval time2)215 elapsed(
216     struct timeval time1,
217     struct timeval time2)
218 {
219     struct timeval etime;
220 
221     /*sanity check, some of the files have packets out of order */
222     if (tv_lt(time2,time1)) {
223 	return(0.0);
224     }
225 
226     if (0) {
227 	fprintf(stderr,"elapsed(%s,", ts2ascii(&time1));
228 	fprintf(stderr,"%s) is ", ts2ascii(&time2));
229     }
230 
231     etime = time2;
232     tv_sub(&etime, time1);
233 
234     if (0)
235 	fprintf(stderr,"\n\t%s \n", ts2ascii(&etime));
236 
237     return((double)etime.tv_sec * 1000000 + (double)etime.tv_usec);
238 }
239 
240 
241 
242 /* subtract the rhs from the lhs, result in lhs */
243 void
tv_sub(struct timeval * plhs,struct timeval rhs)244 tv_sub(struct timeval *plhs, struct timeval rhs)
245 {
246     /* sanity check, lhs MUST BE more than rhs */
247     if (tv_lt(*plhs,rhs)) {
248 	fprintf(stderr,"tvsub(%s,", ts2ascii(plhs));
249 	fprintf(stderr,"%s) bad timestamp order!\n", ts2ascii(&rhs));
250 /* 	exit(-1); */
251 	plhs->tv_sec = plhs->tv_usec = 0;
252 	return;
253     }
254 
255     if (plhs->tv_usec >= rhs.tv_usec) {
256 	plhs->tv_usec -= rhs.tv_usec;
257     } else if (plhs->tv_usec < rhs.tv_usec) {
258 	plhs->tv_usec += US_PER_SEC - rhs.tv_usec;
259 	plhs->tv_sec -= 1;
260     }
261     plhs->tv_sec -= rhs.tv_sec;
262 }
263 
264 
265 /* add the RHS to the LHS, answer in *plhs */
266 void
tv_add(struct timeval * plhs,struct timeval rhs)267 tv_add(struct timeval *plhs, struct timeval rhs)
268 {
269     plhs->tv_sec += rhs.tv_sec;
270     plhs->tv_usec += rhs.tv_usec;
271 
272     if (plhs->tv_usec >= US_PER_SEC) {
273 	plhs->tv_usec -= US_PER_SEC;
274 	plhs->tv_sec += 1;
275     }
276 }
277 
278 
279 /* are the 2 times the same? */
280 Bool
tv_same(struct timeval lhs,struct timeval rhs)281 tv_same(struct timeval lhs, struct timeval rhs)
282 {
283     return((lhs.tv_sec  == rhs.tv_sec) &&
284 	   (lhs.tv_usec == rhs.tv_usec));
285 }
286 
287 
288 /*  1: lhs >  rhs */
289 /*  0: lhs == rhs */
290 /* -1: lhs <  rhs */
291 int
tv_cmp(struct timeval lhs,struct timeval rhs)292 tv_cmp(struct timeval lhs, struct timeval rhs)
293 {
294     if (lhs.tv_sec > rhs.tv_sec) {
295 	return(1);
296     }
297 
298     if (lhs.tv_sec < rhs.tv_sec) {
299 	return(-1);
300     }
301 
302     /* ... else, seconds are the same */
303     if (lhs.tv_usec > rhs.tv_usec)
304 	return(1);
305     else if (lhs.tv_usec == rhs.tv_usec)
306 	return(0);
307     else
308 	return(-1);
309 }
310 
311 
312 
313 /* copy the IP addresses and port numbers into an addrblock structure	*/
314 /* in addition to copying the address, we also create a HASH value	*/
315 /* which is based on BOTH IP addresses and port numbers.  It allows	*/
316 /* faster comparisons most of the time					*/
317 void
CopyAddr(tcp_pair_addrblock * ptpa,struct ip * pip,portnum port1,portnum port2)318 CopyAddr(
319     tcp_pair_addrblock *ptpa,
320     struct ip *pip,
321     portnum	port1,
322     portnum	port2)
323 {
324     ptpa->a_port = port1;
325     ptpa->b_port = port2;
326 
327     if (PIP_ISV4(pip)) { /* V4 */
328 	IP_COPYADDR(&ptpa->a_address, IPV4ADDR2ADDR(&pip->ip_src));
329 	IP_COPYADDR(&ptpa->b_address, IPV4ADDR2ADDR(&pip->ip_dst));
330 	/* fill in the hashed address */
331 	ptpa->hash = ptpa->a_address.un.ip4.s_addr
332 	    + ptpa->b_address.un.ip4.s_addr
333 	    + ptpa->a_port + ptpa->b_port;
334 
335     } else { /* V6 */
336 	int i;
337 	struct ipv6 *pip6 = (struct ipv6 *)pip;
338 	IP_COPYADDR(&ptpa->a_address, IPV6ADDR2ADDR(&pip6->ip6_saddr));
339 	IP_COPYADDR(&ptpa->b_address, IPV6ADDR2ADDR(&pip6->ip6_daddr));
340 	/* fill in the hashed address */
341 	ptpa->hash = ptpa->a_port + ptpa->b_port;
342 	for (i=0; i < 16; ++i) {
343 	    ptpa->hash += ptpa->a_address.un.ip6.s6_addr[i];
344 	    ptpa->hash += ptpa->b_address.un.ip6.s6_addr[i];
345 	}
346     }
347 
348     if (debug > 3)
349 	printf("Hash of (%s:%d,%s:%d) is %d\n",
350 	       HostName(ptpa->a_address),
351 	       ptpa->a_port,
352 	       HostName(ptpa->b_address),
353 	       ptpa->b_port,
354 	       ptpa->hash);
355 }
356 
357 /*
358  * This function tells us which way to go (Left or Right) in search for our
359  * matching 4-tuple {IP1:port1; IP2:port2} in the AVL tree hash-bucket.
360  *
361  * It returns LT or RT depending on if we had to go left or right in the AVL Tree to
362  * find our exact 4-tuple match, if it existed in the tree.
363  * If the exact 4-tuple is found, it returns 0.
364  */
365 
366 int
AVL_WhichDir(tcp_pair_addrblock * ptpa1,tcp_pair_addrblock * ptpa2)367 AVL_WhichDir(
368 	     tcp_pair_addrblock *ptpa1,
369 	     tcp_pair_addrblock *ptpa2)
370 {
371 
372     /*
373      * Here is our algorithm. If ptpa1={x1:p1; x2:p2} and ptpa2={y1:q1; y2:q2}
374      * we choose X1=min(x1,x2) and X2=max(x1,x2); Similarly for Y1, Y2.
375      * P1=port associated with X1, i.e. it is p1 if x1<x2 and it is p2 if not.
376      * P2=port associated with X2. Similarly Q1, Q2 are calculated based on Y1,Y2.
377      *
378      * Compare (X1, Y1)? ; X1<Y1 => LEFT; X1>Y1 => RIGHT; X1==Y1 => Continue down
379      *
380      * Compare (X2, Y2)? ; X2<Y2 => LEFT; X2>Y2 => RIGHT; X2==Y2 => Continue down
381      *
382      * Compare (P1, Q1)? ; P1<Q1 => LEFT; P1>Q1 => RIGHT; P1==Q1 => Continue down
383      *
384      * Compare (P2, Q2)? ; P2<Q2 => LEFT; P2>Q2 => RIGHT;
385      *
386      * If P2==Q2, then this connection should have matched the A2B or B2A catch
387      * from WhichDir()
388      */
389 
390     ipaddr *X1, *X2, *Y1, *Y2;
391     int P1, P2, Q1, Q2;
392 
393     if (IP_LOWADDR(&(ptpa1->a_address), &(ptpa1->b_address))) {
394         X1=&ptpa1->a_address;
395 	P1=ptpa1->a_port;
396 	X2=&ptpa1->b_address;
397 	P2=ptpa1->b_port;
398     }
399     else {
400         X1=&ptpa1->b_address;
401 	P1=ptpa1->b_port;
402 	X2=&ptpa1->a_address;
403 	P2=ptpa1->a_port;
404     }
405 
406     if (IP_LOWADDR(&(ptpa2->a_address), &(ptpa2->b_address))) {
407         Y1=&ptpa2->a_address;
408 	Q1=ptpa2->a_port;
409 	Y2=&ptpa2->b_address;
410 	Q2=ptpa2->b_port;
411     }
412     else {
413         Y1=&ptpa2->b_address;
414 	Q1=ptpa2->b_port;
415  	Y2=&ptpa2->a_address;
416 	Q2=ptpa2->a_port;
417     }
418 
419     // Optimization suggested by Dr.Ostermann. Check the ports first.
420     if (P1<Q1) return LT;
421     if (Q1<P1) return RT;
422 
423     if (P2<Q2) return LT;
424     if (Q2<P2) return RT;
425 
426 
427     if (IP_LOWADDR(X1,Y1)) return LT;
428     if (IP_LOWADDR(Y1,X1)) return RT;
429 
430     if (IP_LOWADDR(X2,Y2)) return LT;
431     if (IP_LOWADDR(Y2,X2)) return RT;
432 
433     return 0;
434 }
435 
436 int
WhichDir(tcp_pair_addrblock * ptpa1,tcp_pair_addrblock * ptpa2)437   WhichDir(
438 	       tcp_pair_addrblock *ptpa1,
439 	       tcp_pair_addrblock *ptpa2)
440 {
441 #ifdef BROKEN_COMPILER
442    /* sorry for the ugly nested 'if', but a 4-way conjunction broke my*/
443    /* Optimizer (under 'gcc version cygnus-2.0.2')*/
444 
445    /* same as first packet */
446    if (IP_SAMEADDR(&(ptpa1->a_address), &(ptpa2->a_address)))
447      if (IP_SAMEADDR(&(ptpa1->b_address), &(ptpa2->b_address)))
448        if ((ptpa1->a_port == ptpa2->a_port))
449 	 if ((ptpa1->b_port == ptpa2->b_port))
450 	   return(A2B);
451 
452    /* reverse of first packet */
453    if (IP_SAMEADDR(&(ptpa1->a_address), &(ptpa2->b_address)))
454      if (IP_SAMEADDR(&(ptpa1->b_address), &(ptpa2->a_address)))
455        if ((ptpa1->a_port == ptpa2->b_port))
456 	 if ((ptpa1->b_port == ptpa2->a_port))
457 	   return(B2A);
458 #else /* BROKEN_COMPILER */
459    /* same as first packet */
460    if (IP_SAMEADDR(&(ptpa1->a_address), &(ptpa2->a_address)) &&
461        IP_SAMEADDR(&(ptpa1->b_address), &(ptpa2->b_address)) &&
462        (ptpa1->a_port == ptpa2->a_port) &&
463        (ptpa1->b_port == ptpa2->b_port))
464      return(A2B);
465 
466    /* reverse of first packet */
467    if (IP_SAMEADDR(&(ptpa1->a_address), &(ptpa2->b_address)) &&
468        IP_SAMEADDR(&(ptpa1->b_address), &(ptpa2->a_address)) &&
469        (ptpa1->a_port == ptpa2->b_port) &&
470        (ptpa1->b_port == ptpa2->a_port))
471      return(B2A);
472 #endif /* BROKEN_COMPILER */
473 
474    /* different connection */
475    return(0);
476 }
477 
478 int
SameConn(tcp_pair_addrblock * ptpa1,tcp_pair_addrblock * ptpa2,int * pdir)479 SameConn(
480 	 tcp_pair_addrblock *ptpa1,
481 	 tcp_pair_addrblock *ptpa2,
482 	 int      *pdir)
483 {
484 
485    /* if the hash values are different, they can't be the same */
486    if (ptpa1->hash != ptpa2->hash)
487      return(0);
488 
489    /* OK, they hash the same, are they REALLY the same function */
490    *pdir = WhichDir(ptpa1,ptpa2);
491    return(*pdir != 0);
492 }
493 
494 
495 
496 static tcp_pair *
NewTTP(struct ip * pip,struct tcphdr * ptcp)497 NewTTP(
498     struct ip *pip,
499     struct tcphdr *ptcp)
500 {
501     char title[210];
502     tcp_pair *ptp;
503 
504     if (0) {
505       printf("trace.c:NewTTP() calling MakeTcpPair()\n");
506     }
507     ptp = MakeTcpPair();
508     ++num_tcp_pairs;
509 
510     if (!run_continuously) {
511       /* make a new one, if possible */
512       if ((num_tcp_pairs+1) >= max_tcp_pairs) {
513 	MoreTcpPairs(num_tcp_pairs+1);
514       }
515       /* create a new TCP pair record and remember where you put it */
516       ttp[num_tcp_pairs] = ptp;
517       ptp->ignore_pair = ignore_pairs[num_tcp_pairs];
518     }
519 
520 
521     /* grab the address from this packet */
522     CopyAddr(&ptp->addr_pair,
523 	     pip, ntohs(ptcp->th_sport), ntohs(ptcp->th_dport));
524 
525     ptp->a2b.time.tv_sec = -1;
526     ptp->b2a.time.tv_sec = -1;
527 
528     ptp->a2b.host_letter = strdup(NextHostLetter());
529     ptp->b2a.host_letter = strdup(NextHostLetter());
530 
531     ptp->a2b.ptp = ptp;
532     ptp->b2a.ptp = ptp;
533     ptp->a2b.ptwin = &ptp->b2a;
534     ptp->b2a.ptwin = &ptp->a2b;
535 
536     /* fill in connection name fields */
537     ptp->a_hostname = strdup(HostName(ptp->addr_pair.a_address));
538     ptp->a_portname = strdup(ServiceName(ptp->addr_pair.a_port));
539     ptp->a_endpoint =
540 	strdup(EndpointName(ptp->addr_pair.a_address,
541 			    ptp->addr_pair.a_port));
542     ptp->b_hostname = strdup(HostName(ptp->addr_pair.b_address));
543     ptp->b_portname = strdup(ServiceName(ptp->addr_pair.b_port));
544     ptp->b_endpoint =
545 	strdup(EndpointName(ptp->addr_pair.b_address,
546 			    ptp->addr_pair.b_port));
547 
548     /* make the initial guess that each side is a reno tcp */
549     /* this might actually be a poor thing to do in the sense that
550        we could be looking at a Tahoe trace ... but the only side
551        effect for the moment is that the LEAST estimate may be
552        busted, although it very well may not be */
553     ptp->a2b.tcp_strain = TCP_RENO;
554     ptp->b2a.tcp_strain = TCP_RENO;
555 
556     ptp->a2b.LEAST = ptp->b2a.LEAST = 0;
557     ptp->a2b.in_rto = ptp->b2a.in_rto = FALSE;
558 
559     /* init time sequence graphs */
560     ptp->a2b.tsg_plotter = ptp->b2a.tsg_plotter = NO_PLOTTER;
561     if (graph_tsg && !ptp->ignore_pair) {
562 	if (!ignore_non_comp || (SYN_SET(ptcp))) {
563 	    snprintf(title,sizeof(title),"%s_==>_%s (time sequence graph)",
564 		    ptp->a_endpoint, ptp->b_endpoint);
565 	    ptp->a2b.tsg_plotter =
566 		new_plotter(&ptp->a2b,NULL,title,
567 			    graph_time_zero?"relative time":"time",
568 			    graph_seq_zero?"sequence offset":"sequence number",
569 			    PLOT_FILE_EXTENSION);
570 	    snprintf(title,sizeof(title),"%s_==>_%s (time sequence graph)",
571 		    ptp->b_endpoint, ptp->a_endpoint);
572 	    ptp->b2a.tsg_plotter =
573 		new_plotter(&ptp->b2a,NULL,title,
574 			    graph_time_zero?"relative time":"time",
575 			    graph_seq_zero?"sequence offset":"sequence number",
576 			    PLOT_FILE_EXTENSION);
577 	    if (graph_time_zero) {
578 		/* set graph zero points */
579 		plotter_nothing(ptp->a2b.tsg_plotter, current_time);
580 		plotter_nothing(ptp->b2a.tsg_plotter, current_time);
581 	    }
582 	}
583     }
584 
585     /* init owin graphs */
586     ptp->a2b.owin_plotter = ptp->b2a.owin_plotter = NO_PLOTTER;
587     if (graph_owin && !ptp->ignore_pair) {
588 	if (!ignore_non_comp || (SYN_SET(ptcp))) {
589 	    snprintf(title,sizeof(title),"%s_==>_%s (outstanding data)",
590 		    ptp->a_endpoint, ptp->b_endpoint);
591 	    ptp->a2b.owin_plotter =
592 		new_plotter(&ptp->a2b,NULL,title,
593 			    graph_time_zero?"relative time":"time",
594 			    "Outstanding Data (bytes)",
595 			    OWIN_FILE_EXTENSION);
596 	    snprintf(title,sizeof(title),"%s_==>_%s (outstanding data)",
597 		    ptp->b_endpoint, ptp->a_endpoint);
598 	    ptp->b2a.owin_plotter =
599 		new_plotter(&ptp->b2a,NULL,title,
600 			    graph_time_zero?"relative time":"time",
601 			    "Outstanding Data (bytes)",
602 			    OWIN_FILE_EXTENSION);
603 	    if (graph_time_zero) {
604 		/* set graph zero points */
605 		plotter_nothing(ptp->a2b.owin_plotter, current_time);
606 		plotter_nothing(ptp->b2a.owin_plotter, current_time);
607 	    }
608 	    ptp->a2b.owin_line =
609 		new_line(ptp->a2b.owin_plotter, "owin", "red");
610 	    ptp->b2a.owin_line =
611 		new_line(ptp->b2a.owin_plotter, "owin", "red");
612 
613 	    if (show_rwinline) {
614 	      ptp->a2b.rwin_line =
615 	        new_line(ptp->a2b.owin_plotter, "rwin", "yellow");
616 	      ptp->b2a.rwin_line =
617 	        new_line(ptp->b2a.owin_plotter, "rwin", "yellow");
618 	    }
619 
620 	    ptp->a2b.owin_avg_line =
621 		new_line(ptp->a2b.owin_plotter, "avg owin", "blue");
622 	    ptp->b2a.owin_avg_line =
623 		new_line(ptp->b2a.owin_plotter, "avg owin", "blue");
624 	    ptp->a2b.owin_wavg_line =
625 		new_line(ptp->a2b.owin_plotter, "wavg owin", "green");
626 	    ptp->b2a.owin_wavg_line =
627 		new_line(ptp->b2a.owin_plotter, "wavg owin", "green");
628 	}
629     }
630 
631     /* init time line graphs (Avinash, 2 July 2002) */
632     ptp->a2b.tline_plotter = ptp->b2a.tline_plotter = NO_PLOTTER;
633     if (graph_tline && !ptp->ignore_pair) {
634 	if (!ignore_non_comp || (SYN_SET(ptcp))) {
635 	    /* We don't want the standard a2b type name so we will specify
636 	     * a filename of type a_b when we call new_plotter.
637 	     */
638 	    char filename[25];
639 	    snprintf(filename,sizeof(filename),"%s_%s",
640 		     ptp->a2b.host_letter, ptp->a2b.ptwin->host_letter);
641 
642 	    snprintf(title,sizeof(title),"%s_==>_%s (time line graph)",
643 		    ptp->a_endpoint, ptp->b_endpoint);
644 	    /* We will keep both the plotters the same since we want all
645 	     * segments going in either direction to be plotted on the same
646 	     * graph
647 	     */
648 	    ptp->a2b.tline_plotter = ptp->b2a.tline_plotter =
649 		new_plotter(&ptp->a2b,filename,title,
650 			    "segments",
651 			    "relative time",
652 			    TLINE_FILE_EXTENSION);
653 
654 	    /* Switch the x & y axis types.
655 	     * The default is x - timeval, y - unsigned,
656 	     * we need x - unsigned, y - dtime.
657 	     * Both the plotters are the same so we will
658 	     * only call this function once.
659 	     */
660 	    plotter_switch_axis(ptp->a2b.tline_plotter, TRUE);
661 
662 	    /* set graph zero points */
663 	    plotter_nothing(ptp->a2b.tline_plotter, current_time);
664 	    plotter_nothing(ptp->b2a.tline_plotter, current_time);
665 
666 	    /* Some graph initializations
667 	     * Generating a drawing space between x=0-100.
668 	     * The time lines will be at x=40 for source, x=60 for destination.
669 	     * Rest of the area on either sides will be used to print segment
670 	     * information.
671 	     *
672 	     *  seg info |----->|
673 	     *           |<-----| seg info
674 	     */
675 	    tline_left  = 40;
676 	    tline_right = 60;
677 	    plotter_invisible(ptp->a2b.tline_plotter, current_time, 0);
678 	    plotter_invisible(ptp->a2b.tline_plotter, current_time, 100);
679 	}
680     }
681 
682 
683     /* init segment size graphs */
684     ptp->a2b.segsize_plotter = ptp->b2a.segsize_plotter = NO_PLOTTER;
685     if (graph_segsize && !ptp->ignore_pair) {
686 	snprintf(title,sizeof(title),"%s_==>_%s (segment size graph)",
687 		ptp->a_endpoint, ptp->b_endpoint);
688 	ptp->a2b.segsize_plotter =
689 	    new_plotter(&ptp->a2b,NULL,title,
690 			graph_time_zero?"relative time":"time",
691 			"segment size (bytes)",
692 			SEGSIZE_FILE_EXTENSION);
693 	snprintf(title,sizeof(title),"%s_==>_%s (segment size graph)",
694 		ptp->b_endpoint, ptp->a_endpoint);
695 	ptp->b2a.segsize_plotter =
696 	    new_plotter(&ptp->b2a,NULL,title,
697 			graph_time_zero?"relative time":"time",
698 			"segment size (bytes)",
699 			SEGSIZE_FILE_EXTENSION);
700 	if (graph_time_zero) {
701 	    /* set graph zero points */
702 	    plotter_nothing(ptp->a2b.segsize_plotter, current_time);
703 	    plotter_nothing(ptp->b2a.segsize_plotter, current_time);
704 	}
705 	ptp->a2b.segsize_line =
706 	    new_line(ptp->a2b.segsize_plotter, "segsize", "red");
707 	ptp->b2a.segsize_line =
708 	    new_line(ptp->b2a.segsize_plotter, "segsize", "red");
709 	ptp->a2b.segsize_avg_line =
710 	    new_line(ptp->a2b.segsize_plotter, "avg segsize", "blue");
711 	ptp->b2a.segsize_avg_line =
712 	    new_line(ptp->b2a.segsize_plotter, "avg segsize", "blue");
713     }
714 
715     /* init RWIN graphs */
716     ptp->a2b.recvwin_plotter = ptp->b2a.recvwin_plotter = NO_PLOTTER;
717     if (graph_recvwin && !ptp->ignore_pair) {
718 	snprintf(title,sizeof(title),"%s_==>_%s (advertised receive window graph)",
719 		ptp->a_endpoint, ptp->b_endpoint);
720 	ptp->a2b.recvwin_plotter =
721 	    new_plotter(&ptp->a2b,NULL,title,
722 			graph_time_zero?"relative time":"time",
723 			"advertised window (bytes)",
724 			RECVWIN_FILE_EXTENSION);
725 	snprintf(title,sizeof(title),"%s_==>_%s (advertised receive window graph)",
726 		ptp->b_endpoint, ptp->a_endpoint);
727 	ptp->b2a.recvwin_plotter =
728 	    new_plotter(&ptp->b2a,NULL,title,
729 			graph_time_zero?"relative time":"time",
730 			"advertised window (bytes)",
731 			RECVWIN_FILE_EXTENSION);
732 	if (graph_time_zero) {
733 	    /* set graph zero points */
734 	    plotter_nothing(ptp->a2b.recvwin_plotter, current_time);
735 	    plotter_nothing(ptp->b2a.recvwin_plotter, current_time);
736 	}
737 	ptp->a2b.recvwin_line =
738 	    new_line(ptp->a2b.recvwin_plotter, "recvwin", "red");
739 	ptp->b2a.recvwin_line =
740 	    new_line(ptp->b2a.recvwin_plotter, "recvwin", "red");
741     }
742 
743     /* init RTT graphs */
744     ptp->a2b.rtt_plotter = ptp->b2a.rtt_plotter = NO_PLOTTER;
745 
746     ptp->a2b.ss = MakeSeqspace();
747     ptp->b2a.ss = MakeSeqspace();
748 
749     ptp->filename = cur_filename;
750 
751     return(ptp);
752 }
753 
754 
755 
756 /* connection records are stored in a hash table.  Buckets are linked	*/
757 /* lists sorted by most recent access.					*/
758 #ifdef SMALL_TABLE
759 #define HASH_TABLE_SIZE 1021  /* oughta be prime */
760 #else /* SMALL_TABLE */
761 #define HASH_TABLE_SIZE 4099  /* oughta be prime */
762 #endif /* SMALL_TABLE */
763 static ptp_snap *ptp_hashtable[HASH_TABLE_SIZE] = {NULL};
764 
765 
766 /* search efficiency data (optional) */
767 /* one entry per hash table bucket */
768 struct search_efficiency {
769     unsigned num_connections;
770     unsigned max_connections;
771     unsigned max_depth;
772     unsigned num_searches;
773     unsigned num_comparisons;
774 };
775 static struct search_efficiency hashtable_efficiency[HASH_TABLE_SIZE];
776 
777 
778 /* double linked-lists of live and closed connections */
779 static ptp_ptr	*live_conn_list_head = NULL;
780 static ptp_ptr	*live_conn_list_tail = NULL;
781 static ptp_ptr	*closed_conn_list_head = NULL;
782 static ptp_ptr	*closed_conn_list_tail = NULL;
783 static timeval	last_update_time = {0, 0};
784 
785 static tcp_pair *
FindTTP(struct ip * pip,struct tcphdr * ptcp,int * pdir,ptp_ptr ** tcp_ptr)786 FindTTP(
787     struct ip *pip,
788     struct tcphdr *ptcp,
789     int *pdir,
790     ptp_ptr **tcp_ptr)
791 {
792     ptp_snap **pptph_head = NULL;
793     ptp_snap *ptph;
794     tcp_pair_addrblock	tp_in;
795     struct search_efficiency *pse = NULL;
796     unsigned depth = 0;
797     int dir, conn_status;
798     hash hval;
799     *tcp_ptr = NULL;
800 
801     if (debug > 10) {
802 	printf("trace.c: FindTTP() called\n");
803     }
804 
805     /* grab the address from this packet */
806     CopyAddr(&tp_in, pip, ntohs(ptcp->th_sport), ntohs(ptcp->th_dport));
807 
808     /* grab the hash value (already computed by CopyAddr) */
809     hval = tp_in.hash % HASH_TABLE_SIZE;
810 
811     pptph_head = &ptp_hashtable[hval];
812 
813     if (debug) {
814 	/* search efficiency checking */
815 	pse = &hashtable_efficiency[hval];
816     }
817 
818     if (pse) {
819 	/* search efficiency instrumentation */
820 	depth = 0;
821 	++pse->num_searches;
822     }
823 
824     for (ptph = *pptph_head; ptph; ) {
825 	if (debug) {
826 	    /* search efficiency instrumentation */
827 	    ++search_count;
828 	    if (pse) {
829 		++depth;
830 		++pse->num_comparisons;
831 	    }
832 	}
833 
834 	/* See if the current node in the AVL tree hash-bucket
835 	 * is the exact same connection as ourselves,
836 	 * either in A2B or B2A directions.
837 	 */
838 
839 	dir = WhichDir(&tp_in, &ptph->addr_pair);
840 
841 	if (dir == A2B || dir == B2A) {
842 	    /* OK, this looks good, suck it into memory */
843 
844 	    tcb *thisdir;
845 	    tcb *otherdir;
846 	    tcp_pair *ptp;
847 	    if (run_continuously) {
848 		ptp_ptr *ptr = (ptp_ptr *)ptph->ptp;
849 		ptp = ptr->ptp;
850 	    }
851 	    else {
852 		ptp = (tcp_pair *)ptph->ptp;
853 	    }
854 
855 	    /* figure out which direction this packet is going */
856 	    if (dir == A2B) {
857 		thisdir  = &ptp->a2b;
858 		otherdir = &ptp->b2a;
859 	    } else {
860 		thisdir  = &ptp->b2a;
861 		otherdir = &ptp->a2b;
862 	    }
863 
864 	    /* check for "inactive" */
865 	    /* (this shouldn't happen anymore, they aren't on the list */
866 	    if (ptp->inactive) {
867 
868 		if (!run_continuously)
869 		    continue;
870 		else {
871 		    *tcp_ptr = (ptp_ptr *)ptph->ptp;
872 		    return ((*tcp_ptr)->ptp);
873 		}
874 	    }
875 
876 
877 	    /* Fri Oct 16, 1998 */
878 	    /* note: original heuristic was not sufficient.  Bugs */
879 	    /* were pointed out by Brian Utterback and later by */
880 	    /* myself and Mark Allman */
881 
882 	    if (!run_continuously) {
883 		/* check for NEW connection on these same endpoints */
884 		/* 1) At least 4 minutes idle time */
885 		/*  OR */
886 		/* 2) heuristic (we might miss some) either: */
887 		/*    this packet has a SYN */
888 		/*    last conn saw both FINs and/or RSTs */
889 		/*    SYN sequence number outside last window (rfc 1122) */
890 		/*      (or less than initial Sequence, */
891 		/*       for wrap around trouble)  - Tue Nov  3, 1998*/
892 		/*  OR */
893 		/* 3) this is a SYN, last had a SYN, seq numbers differ */
894 		/* if so, mark it INACTIVE and skip from now on */
895 		if (0 && SYN_SET(ptcp)) {
896 		    /* better keep this debugging around, it keeps breaking */
897 		    printf("elapsed: %f sec\n",
898 			   elapsed(ptp->last_time,current_time)/1000000);
899 		    printf("SYN_SET: %d\n", SYN_SET(ptcp));
900 		    printf("a2b.fin_count: %d\n", ptp->a2b.fin_count);
901 		    printf("b2a.fin_count: %d\n", ptp->b2a.fin_count);
902 		    printf("a2b.reset_count: %d\n", ptp->a2b.reset_count);
903 		    printf("b2a.reset_count: %d\n", ptp->b2a.reset_count);
904 		    printf("dir: %d (%s)\n", dir, dir==A2B?"A2B":"B2A");
905 		    printf("seq:    %lu \n", (u_long)ntohl(ptcp->th_seq));
906 		    printf("winend: %lu \n", otherdir->windowend);
907 		    printf("syn:    %lu \n", otherdir->syn);
908 		    printf("SEQ_GREATERTHAN winend: %d\n",
909 			   SEQ_GREATERTHAN(ntohl(ptcp->th_seq),otherdir->windowend));
910 		    printf("SEQ_LESSTHAN init syn: %d\n",
911 			   SEQ_LESSTHAN(ntohl(ptcp->th_seq),thisdir->syn));
912 		}
913 
914 		if (/* rule 1 */
915 		    (elapsed(ptp->last_time,current_time)/1000000 > nonreal_live_conn_interval)//(4*60)) - Using nonreal_live_conn_interval instead of the 4 mins heuristic
916 		    || /* rule 2 */
917 		    ((SYN_SET(ptcp)) &&
918 		     (((thisdir->fin_count >= 1) ||
919 		       (otherdir->fin_count >= 1)) ||
920 		      ((thisdir->reset_count >= 1) ||
921 		       (otherdir->reset_count >= 1))) &&
922 		     (SEQ_GREATERTHAN(ntohl(ptcp->th_seq),otherdir->windowend) ||
923 		      SEQ_LESSTHAN(ntohl(ptcp->th_seq),thisdir->syn)))
924 		    || /* rule 3 */
925 		    (SYN_SET(ptcp) &&
926 		     (thisdir->syn_count > 1) &&
927 		     (thisdir->syn != ntohl(ptcp->th_seq)))) {
928 
929 		    if (debug>1) {
930 			printf("%s: Marking %p %s<->%s INACTIVE (idle: %f sec)\n",
931 			       ts2ascii(&current_time),
932 			       ptp,
933 			       ptp->a_endpoint, ptp->b_endpoint,
934 			       elapsed(ptp->last_time,
935 				       current_time)/1000000);
936 			if (debug > 3)
937 			    PrintTrace(ptp);
938 		    }
939 
940 		    /* we won't need this one anymore, remove it from the */
941 		    /* hash table so we won't have to skip over it */
942 		    ptp->inactive = TRUE;
943 
944 		    if (debug > 4)
945 			printf("Removing connection from hashtable:\
946                           FindTTP() calling SnapRemove()\n");
947 
948 		    /* Removes connection snapshot from AVL tree */
949 		    SnapRemove(pptph_head, ptph->addr_pair);
950 
951 		    break;
952 		}
953 	    }
954 
955 	    if (run_continuously)
956 		(*tcp_ptr) = (ptp_ptr *)ptph->ptp;
957 
958 	    *pdir = dir;
959 	    return (ptp);
960 	} else {  // WhichDir returned 0, meaning if it exists, it's deeper
961 	    conn_status = AVL_WhichDir(&tp_in,&ptph->addr_pair);
962 	    if (conn_status == LT)
963 		ptph = ptph->left;
964 	    else if (conn_status == RT)
965 		ptph = ptph->right;
966 	    else if (!conn_status)  {
967 		fprintf(stderr, "WARNING!! AVL_WhichDir() should not return 0 if\n"
968 				"\tWhichDir() didn't return A2B or B2A previously\n");
969 		break;
970 	    }
971 	}
972     }
973 
974 
975     /* Didn't find it, make a new one, if possible */
976     if (0) {
977 	printf("trace.c:FindTTP() calling MakePtpSnap()\n");
978     }
979     ptph = MakePtpSnap();
980 
981     if (run_continuously) {
982 	ptp_ptr *ptr = (ptp_ptr *)MakePtpPtr();
983 	ptr->prev = NULL;
984 
985 	if (live_conn_list_head == NULL) {
986 	    ptr->next = NULL;
987 	    live_conn_list_head = ptr;
988 	    live_conn_list_tail = ptr;
989 	}
990 	else {
991 	    ptr->next = live_conn_list_head;
992 	    live_conn_list_head->prev = ptr;
993 	    live_conn_list_head = ptr;
994 	}
995 	ptr->from = ptph;
996 	ptr->ptp = NewTTP(pip, ptcp);
997 	ptph->addr_pair = ptr->ptp->addr_pair;
998 	ptph->ptp = (void *)ptr;
999 	if (conn_num_threshold) {
1000 	    active_conn_count++;
1001 	    if (active_conn_count > max_conn_num) {
1002 		ptp_ptr *last_ptr = live_conn_list_tail;
1003 		live_conn_list_tail = last_ptr->prev;
1004 		live_conn_list_tail->next = NULL;
1005 		RemoveConn(last_ptr);
1006 		num_removed_tcp_pairs++;
1007 		active_conn_count--;
1008 		FreePtpPtr(last_ptr);
1009 	    }
1010 	}
1011     }
1012     else {
1013 	tcp_pair *tmp = NewTTP(pip,ptcp);
1014 	ptph->addr_pair = tmp->addr_pair;
1015 	ptph->ptp = tmp;
1016     }
1017 
1018     /* To insert the new connection snapshot into the AVL tree */
1019 
1020     if (debug > 4)
1021 	printf("Inserting connection into hashtable:\
1022              FindTTP() calling SnapInsert() \n");
1023     SnapInsert(pptph_head, ptph);
1024 
1025     if (pse) {
1026 	/* search efficiency instrumentation */
1027 	++pse->num_connections;
1028 	if (depth > pse->max_depth)
1029 	    pse->max_depth = depth;
1030 	if (pse->num_connections > pse->max_connections)
1031 	    pse->max_connections = pse->num_connections;
1032     }
1033 
1034 
1035     *pdir = A2B;
1036     if (run_continuously) {
1037 	*tcp_ptr = (ptp_ptr *)ptph->ptp;
1038 	return ((*tcp_ptr)->ptp);
1039     }
1040     else
1041 	return (tcp_pair *)(ptph->ptp);
1042 }
1043 
1044 static void
UpdateConnLists(ptp_ptr * tcp_ptr,struct tcphdr * ptcp)1045 UpdateConnLists(
1046 		ptp_ptr *tcp_ptr,
1047 		struct tcphdr *ptcp)
1048 {
1049   time_t real_time;
1050   static int minutes = 0;
1051 
1052   if (0) {
1053     printf("trace.c: UpdateConnLists() called\n");
1054   }
1055 
1056   if ((FinCount(tcp_ptr->ptp) > 0) || (ConnReset(tcp_ptr->ptp))) {
1057     /* we have FIN or RST */
1058     if (!tcp_ptr->ptp->inactive) {
1059        /* this is the only FIN or new RST - remove from list of active conns */
1060       if (debug > 6) {
1061 	printf("UpdateConnLists: removing conn from list of active conns\n");
1062       }
1063       UpdateConnList(tcp_ptr, FALSE,
1064 		     &live_conn_list_head,
1065 		     &live_conn_list_tail);
1066       tcp_ptr->ptp->inactive = TRUE;
1067 
1068       if (conn_num_threshold) {
1069 	active_conn_count--;
1070 	closed_conn_count++;
1071 	if (closed_conn_count > max_conn_num) {
1072 	  ptp_ptr *last_ptr = closed_conn_list_tail;
1073 	  closed_conn_list_tail = last_ptr->prev;
1074 	  closed_conn_list_tail->next = NULL;
1075 	  RemoveConn(last_ptr);
1076 	  num_removed_tcp_pairs++;
1077 	  closed_conn_count--;
1078 	  FreePtpPtr(last_ptr);
1079 	}
1080       }
1081 
1082       /* put entry into the list of inactive connections */
1083       if (closed_conn_list_head) {
1084 	tcp_ptr->next = closed_conn_list_head;
1085 	tcp_ptr->prev = NULL;
1086 	closed_conn_list_head->prev = tcp_ptr;
1087 	closed_conn_list_head = tcp_ptr;
1088       }
1089       else {
1090 	tcp_ptr->next = NULL;
1091 	tcp_ptr->prev = NULL;
1092 	closed_conn_list_head = tcp_ptr;
1093 	closed_conn_list_tail = tcp_ptr;
1094       }
1095     }
1096     else {
1097     /* update the list of closed connecitons */
1098     UpdateConnList(tcp_ptr, TRUE, &closed_conn_list_head,
1099 		   &closed_conn_list_tail);
1100     }
1101   }
1102   else {/* don't have FIN(s)/RST */
1103     /* update only list of active connections */
1104      if (tcp_ptr->ptp->inactive == TRUE) {
1105 	printf("WARNING!!! con is inactive, ptr=%p, con=%p, fin=%i, rst=%i\n", tcp_ptr,
1106 	       tcp_ptr->ptp, FinCount(tcp_ptr->ptp), ConnReset(tcp_ptr->ptp));
1107 	printf("a2b.reset_count=%i, b2a.reset_count=%i, RESET_SET(tcph)=%i\n",
1108 	       tcp_ptr->ptp->a2b.reset_count, tcp_ptr->ptp->b2a.reset_count,
1109 	       RESET_SET(ptcp));
1110      }
1111     UpdateConnList(tcp_ptr, TRUE, &live_conn_list_head, &live_conn_list_tail);
1112   }
1113 
1114   /* if we haven't updated the structures for at least update_interval number
1115    * of seconds, update list of connections and hash table */
1116   if ((elapsed(last_update_time, current_time) / 1000000) >= update_interval) {
1117 
1118     real_time = time(&real_time);
1119     if (debug > 10)
1120       fprintf(stderr, "%3i program time: %i\tcurrent time: %i\tdifference: %i\n",
1121               ++minutes, (int)current_time.tv_sec, (int)real_time,
1122               (int)(real_time - current_time.tv_sec));
1123     if (conn_num_threshold) {
1124       RemoveOldConns(&live_conn_list_head,
1125 		     &live_conn_list_tail,
1126 		     remove_live_conn_interval,
1127 		     TRUE,
1128 		     &active_conn_count);
1129       RemoveOldConns(&closed_conn_list_head,
1130 		     &closed_conn_list_tail,
1131 		     remove_closed_conn_interval,
1132 		     TRUE,
1133 		     &closed_conn_count);
1134     }
1135     else {
1136       RemoveOldConns(&live_conn_list_head,
1137 		     &live_conn_list_tail,
1138 		     remove_live_conn_interval,
1139 		     FALSE,
1140 		     0);
1141       RemoveOldConns(&closed_conn_list_head,
1142 		     &closed_conn_list_tail,
1143 		     remove_closed_conn_interval,
1144 		     FALSE,
1145 		     0);
1146     }
1147     last_update_time = current_time;
1148   }
1149 }
1150 
1151 
1152 
1153 static void
UpdateConnList(ptp_ptr * tcp_ptr,const Bool valid,ptp_ptr ** conn_list_head,ptp_ptr ** conn_list_tail)1154 UpdateConnList(
1155 	       ptp_ptr *tcp_ptr,
1156 	       const Bool valid,
1157 	       ptp_ptr **conn_list_head,
1158 	       ptp_ptr **conn_list_tail)
1159 {
1160   ptp_ptr *ptr_prev;
1161   ptp_ptr *ptr_next;
1162 
1163   if (0) {
1164     printf("UpdateConnList() called\n");
1165   }
1166   if (tcp_ptr == (*conn_list_head)) {
1167     if (valid) {
1168       return;
1169     }
1170     else {
1171       *conn_list_head = tcp_ptr->next;
1172       if ((*conn_list_tail) == tcp_ptr)
1173 	*conn_list_tail = NULL;
1174       else
1175 	(*conn_list_head)->prev = NULL;
1176       return;
1177     }
1178   }
1179 
1180   ptr_prev = tcp_ptr->prev;
1181   ptr_next = tcp_ptr->next;
1182 
1183   ptr_prev->next = ptr_next;
1184 
1185   if (ptr_next)
1186     ptr_next->prev = ptr_prev;
1187   if (tcp_ptr == (*conn_list_tail))
1188     *conn_list_tail = ptr_prev;
1189 
1190   if (valid) {
1191     tcp_ptr->next = (*conn_list_head);
1192     tcp_ptr->prev = NULL;
1193     (*conn_list_head)->prev = tcp_ptr;
1194     *conn_list_head = tcp_ptr;
1195   }
1196   return;
1197 }
1198 
1199 
1200 
1201 static void
RemoveOldConns(ptp_ptr ** conn_list_head,ptp_ptr ** conn_list_tail,const unsigned expire_interval,const Bool num_conn_check,int * conn_count)1202 RemoveOldConns(
1203 	       ptp_ptr **conn_list_head,
1204 	       ptp_ptr **conn_list_tail,
1205 	       const unsigned expire_interval,
1206 	       const Bool num_conn_check,
1207 	       int *conn_count)
1208 {
1209   ptp_ptr	*ptr;
1210   ptp_ptr	*prev_ptr;
1211 
1212   if (0) {
1213     printf("trace.c: RemoveOldConns() called\n");
1214   }
1215 
1216   if ((*conn_list_tail) == NULL) {
1217     return;
1218   }
1219 
1220   ptr = (*conn_list_tail);
1221   prev_ptr = ptr->prev;
1222   for (; prev_ptr != NULL; ptr = prev_ptr, prev_ptr = ptr->prev) {
1223     if ((elapsed(ptr->ptp->last_time, current_time) / 1000000) >=
1224 	expire_interval) {
1225       /* if the connection is old enough, remove the snap from the linked-list
1226 	 and the hash_table */
1227       ptr->prev->next = NULL;
1228       *conn_list_tail = ptr->prev;
1229       RemoveConn(ptr);
1230       num_removed_tcp_pairs++;
1231       if (0) {
1232 	printf("trace.c:RemoveOldConns() calling FreePtpSnap()\n");
1233       }
1234       FreePtpPtr(ptr);
1235       if (num_conn_check)
1236 	--(*conn_count);
1237     }
1238     else {
1239       break;
1240     }
1241   }
1242 
1243   if (((*conn_list_head)->ptp->last_time.tv_sec != 0) &&
1244       ((elapsed((*conn_list_head)->ptp->last_time, current_time) / 1000000) >=
1245        expire_interval)) {
1246     *conn_list_head = NULL;
1247     *conn_list_tail = NULL;
1248     RemoveConn(ptr);
1249     num_removed_tcp_pairs++;
1250     FreePtpPtr(ptr);
1251     if (num_conn_check)
1252       --(*conn_count);
1253   }
1254 }
1255 
1256 
1257 
1258 /* remove tcp pair from the hash table */
1259 static void
RemoveConn(const ptp_ptr * tcp_ptr)1260 RemoveConn(
1261 	   const ptp_ptr *tcp_ptr)
1262 {
1263   hash		hval;
1264 
1265    if (0) {
1266       printf("trace.c: RemoveConn(%p %s<->%s) called\n",
1267 	     tcp_ptr->ptp, tcp_ptr->ptp->a_endpoint, tcp_ptr->ptp->b_endpoint);
1268    }
1269 
1270    ModulesPerOldConn(tcp_ptr->ptp);
1271 
1272    hval = tcp_ptr->ptp->addr_pair.hash % HASH_TABLE_SIZE;
1273 
1274    /* Remove the connection snapshot from AVL tree */
1275    if (debug > 4)
1276      printf("Removing connection from hashtable:\
1277              RemoveConn() calling SnapRemove()\n");
1278 
1279    SnapRemove(&ptp_hashtable[hval], tcp_ptr->ptp->addr_pair);
1280 
1281    RemoveTcpPair(tcp_ptr);
1282 }
1283 
1284 
1285 
1286 static void
RemoveTcpPair(const ptp_ptr * tcp_ptr)1287 RemoveTcpPair(
1288 	      const ptp_ptr *tcp_ptr)
1289 {
1290   int	i = 0;
1291   tcp_pair *ptp = tcp_ptr->ptp;
1292 
1293   if (0) {
1294     printf("trace.c: RemoveTcpPair(%p) called\n", tcp_ptr->ptp);
1295   }
1296 
1297   free(ptp->a2b.host_letter);
1298   free(ptp->b2a.host_letter);
1299 
1300   free(ptp->a_hostname);
1301   free(ptp->a_portname);
1302   free(ptp->a_endpoint);
1303 
1304   free(ptp->b_hostname);
1305   free(ptp->b_portname);
1306   free(ptp->b_endpoint);
1307 
1308   if (ptp->a2b.owin_line) {
1309     free(ptp->a2b.owin_line);
1310   }
1311 
1312   if (show_rwinline) {
1313     if (ptp->a2b.rwin_line) {
1314       free(ptp->a2b.rwin_line);
1315     }
1316   }
1317 
1318   if (ptp->a2b.owin_avg_line) {
1319     free(ptp->a2b.owin_avg_line);
1320   }
1321   if (ptp->a2b.owin_wavg_line) {
1322     free(ptp->a2b.owin_avg_line);
1323   }
1324   if (ptp->b2a.owin_line) {
1325     free(ptp->b2a.owin_line);
1326   }
1327 
1328   if (show_rwinline) {
1329     if (ptp->b2a.rwin_line) {
1330       free(ptp->b2a.rwin_line);
1331     }
1332   }
1333 
1334   if (ptp->b2a.owin_avg_line) {
1335     free(ptp->b2a.owin_avg_line);
1336   }
1337   if (ptp->b2a.owin_wavg_line) {
1338     free(ptp->b2a.owin_wavg_line);
1339   }
1340 
1341   if (ptp->a2b.segsize_line) {
1342     free(ptp->a2b.segsize_line);
1343   }
1344   if (ptp->a2b.segsize_avg_line) {
1345     free(ptp->a2b.segsize_avg_line);
1346   }
1347   if (ptp->b2a.segsize_line) {
1348     free(ptp->b2a.segsize_line);
1349   }
1350   if (ptp->b2a.segsize_avg_line) {
1351     free(ptp->b2a.segsize_avg_line);
1352   }
1353 
1354   if (ptp->a2b.recvwin_line) {
1355     free(ptp->a2b.recvwin_line);
1356   }
1357   if (ptp->b2a.recvwin_line) {
1358     free(ptp->b2a.recvwin_line);
1359   }
1360 
1361   if (ptp->a2b.ss) {
1362     for (i = 0; i < 4; i++) {
1363       if (ptp->a2b.ss->pquad[i] != NULL) {
1364 	freequad(&ptp->a2b.ss->pquad[i]);
1365       }
1366     }
1367     FreeSeqspace(ptp->a2b.ss);
1368   }
1369 
1370   if (ptp->b2a.ss) {
1371     for (i = 0; i < 4; i++) {
1372       if (ptp->b2a.ss->pquad[i] != NULL) {
1373 	freequad(&ptp->b2a.ss->pquad[i]);
1374       }
1375     }
1376     FreeSeqspace(ptp->b2a.ss);
1377   }
1378 
1379   FreeTcpPair(ptp);
1380 }
1381 
1382 
1383 
1384 tcp_pair *
dotrace(struct ip * pip,struct tcphdr * ptcp,void * plast)1385 dotrace(
1386     struct ip *pip,
1387     struct tcphdr *ptcp,
1388     void *plast)
1389 {
1390     struct tcp_options *ptcpo;
1391     tcp_pair	*ptp_save;
1392     int		tcp_length;
1393     int		tcp_data_length;
1394     u_long	start;
1395     u_long	end;
1396     tcb		*thisdir;
1397     tcb		*otherdir;
1398     tcp_pair	tp_in;
1399     PLOTTER	to_tsgpl;
1400     PLOTTER	from_tsgpl;
1401     PLOTTER     tlinepl;
1402     int		dir = A2B;	/* initialize to default, always changed below */
1403     Bool	retrans;
1404     Bool 	probe;
1405     Bool	hw_dup = FALSE;	/* duplicate at the hardware level */
1406     Bool	ecn_ce = FALSE;
1407     Bool	ecn_echo = FALSE;
1408     Bool	cwr = FALSE;
1409     Bool        urg = FALSE;
1410     int		retrans_num_bytes;
1411     Bool	out_order;	/* out of order */
1412     u_short	th_sport;	/* source port */
1413     u_short	th_dport;	/* destination port */
1414     tcp_seq	th_seq;		/* sequence number */
1415     tcp_seq	th_ack;		/* acknowledgement number */
1416     u_short	th_win;		/* window */
1417     u_long	eff_win;	/* window after scaling */
1418     u_short     th_urp;         /* URGENT pointer */
1419     short	ip_len;		/* total length */
1420     enum t_ack	ack_type=NORMAL; /* how should we draw the ACK */
1421     seqnum	old_this_windowend; /* for graphing */
1422     ptp_ptr	*tcp_ptr = NULL;
1423 
1424     /* make sure we have enough of the packet */
1425     if ((char *)ptcp + sizeof(struct tcphdr)-1 > (char *)plast) {
1426 	if (warn_printtrunc)
1427 	    fprintf(stderr,
1428 		    "TCP packet %lu truncated too short to trace, ignored\n",
1429 		    pnum);
1430 	++ctrunc;
1431 	return(NULL);
1432     }
1433 
1434 
1435     /* convert interesting fields to local byte order */
1436     th_seq   = ntohl(ptcp->th_seq);
1437     th_ack   = ntohl(ptcp->th_ack);
1438     th_sport = ntohs(ptcp->th_sport);
1439     th_dport = ntohs(ptcp->th_dport);
1440     th_win   = ntohs(ptcp->th_win);
1441     th_urp   = ntohs(ptcp->th_urp);
1442     ip_len   = gethdrlength(pip, plast) + getpayloadlength(pip,plast);
1443 
1444     /* make sure this is one of the connections we want */
1445     ptp_save = FindTTP(pip,ptcp,&dir, &tcp_ptr);
1446 
1447     ++tcp_packet_count;
1448 
1449     if (ptp_save == NULL) {
1450 	return(NULL);
1451     }
1452 
1453     ++tcp_trace_count;
1454 
1455     if (run_continuously && (tcp_ptr == NULL)) {
1456       fprintf(stderr, "Did not initialize tcp pair pointer\n");
1457       exit(1);
1458     }
1459 
1460     /* do time stats */
1461     if (ZERO_TIME(&ptp_save->first_time)) {
1462 	ptp_save->first_time = current_time;
1463     }
1464     ptp_save->last_time = current_time;
1465 
1466 
1467     /* bug fix:  it's legal to have the same end points reused.  The */
1468     /* program uses a heuristic of looking at the elapsed time from */
1469     /* the last packet on the previous instance and the number of FINs */
1470     /* in the last instance.  If we don't increment the fin_count */
1471     /* before bailing out in "ignore_pair" below, this heuristic breaks */
1472 
1473     /* figure out which direction this packet is going */
1474     if (dir == A2B) {
1475 	thisdir  = &ptp_save->a2b;
1476 	otherdir = &ptp_save->b2a;
1477     } else {
1478 	thisdir  = &ptp_save->b2a;
1479 	otherdir = &ptp_save->a2b;
1480     }
1481 
1482     /* meta connection stats */
1483     if (SYN_SET(ptcp))
1484 	++thisdir->syn_count;
1485     if (RESET_SET(ptcp))
1486 	++thisdir->reset_count;
1487     if (FIN_SET(ptcp))
1488 	++thisdir->fin_count;
1489 
1490     /* end bug fix */
1491 
1492 
1493     /* compute the "effective window", which is the advertised window */
1494     /* with scaling */
1495     if (ACK_SET(ptcp) || SYN_SET(ptcp)) {
1496 	eff_win = (u_long) th_win;
1497 
1498 	/* N.B., the window_scale stored for the connection DURING 3way */
1499 	/* handshaking is the REQUESTED scale.  It's only valid if both */
1500 	/* sides request scaling.  AFTER we've seen both SYNs, that field */
1501 	/* is reset (above) to contain zero.  Note that if we */
1502 	/* DIDN'T see the SYNs, the windows will be off. */
1503  	/* Jamshid: Remember that the window is never scaled in SYN */
1504  	/* packets, as per RFC 1323. */
1505  	if (thisdir->f1323_ws && otherdir->f1323_ws && !SYN_SET(ptcp))
1506 	    eff_win <<= thisdir->window_scale;
1507     } else {
1508 	eff_win = 0;
1509     }
1510 
1511 
1512     /* idle-time stats */
1513     if (!ZERO_TIME(&thisdir->last_time)) {
1514 	u_llong itime = elapsed(thisdir->last_time,current_time);
1515 	if (itime > thisdir->idle_max)
1516 	    thisdir->idle_max = itime;
1517     }
1518     thisdir->last_time = current_time;
1519 
1520 
1521     /* calculate data length */
1522     tcp_length = getpayloadlength(pip, plast);
1523     tcp_data_length = tcp_length - (4 * TH_OFF(ptcp));
1524 
1525     /* calc. data range */
1526     start = th_seq;
1527     end = start + tcp_data_length;
1528 
1529     /* seq. space wrap around stats */
1530     /* If all four quadrants have been visited and the current packet
1531      * is in the same quadrant as the syn, check if latest seq. num is
1532      * wrapping past the syn. If it is, increment wrap_count
1533      */
1534     if ((thisdir->quad1 && thisdir->quad2 && thisdir->quad3 && thisdir->quad4)) {
1535 	if ((IN_Q1(thisdir->syn) && (IN_Q1(end))) ||  (IN_Q2(thisdir->syn) && (IN_Q2(end))) || ((IN_Q3(thisdir->syn) && (IN_Q3(end))) || ((IN_Q4(thisdir->syn) && (IN_Q4(end)))))) {
1536 	    if (end >= thisdir->syn) {
1537 		if (debug>1)
1538 		    fprintf(stderr, "\nWARNING : sequence space wrapped around here \n");
1539 		thisdir->seq_wrap_count++;
1540 		thisdir->quad1=0;
1541 		thisdir->quad2=0;
1542 		thisdir->quad3=0;
1543 		thisdir->quad4=0;
1544 	    }
1545 	}
1546     }
1547 
1548     /* Mark the visited quadrants */
1549     if (!thisdir->quad1) {
1550 	if (IN_Q1(start) || IN_Q1(end))
1551 	    thisdir->quad1=1;
1552     }
1553     if (!thisdir->quad2) {
1554 	if (IN_Q2(start) || IN_Q2(end))
1555 	    thisdir->quad2=1;
1556     }
1557     if (!thisdir->quad3) {
1558 	if (IN_Q3(start) || IN_Q3(end))
1559 	    thisdir->quad3=1;
1560     }
1561     if (!thisdir->quad4) {
1562 	if (IN_Q4(start) || IN_Q4(end))
1563 	    thisdir->quad4=1;
1564     }
1565 
1566     /* record sequence limits */
1567     if (SYN_SET(ptcp)) {
1568 	/* error checking - better not change! */
1569 	if ((thisdir->syn_count > 1) && (thisdir->syn != start)) {
1570 	    /* it changed, that shouldn't happen! */
1571 	    if (warn_printbad_syn_fin_seq)
1572 		fprintf(stderr, "\
1573 %s->%s: rexmitted SYN had diff. seqnum! (was %lu, now %lu, etime: %d sec)\n",
1574 			thisdir->host_letter,thisdir->ptwin->host_letter,
1575 			thisdir->syn, start,
1576 			(int)(elapsed(ptp_save->first_time,current_time)/1000000));
1577 	    thisdir->bad_behavior = TRUE;
1578 	}
1579 	thisdir->syn = start;
1580 	otherdir->ack = start;
1581 		/* bug fix for Rob Austein <sra@epilogue.com> */
1582     }
1583     if (FIN_SET(ptcp)) {
1584 	/* bug fix, if there's data here too, we need to bump up the FIN */
1585 	/* (psc data file shows example) */
1586 	u_long fin = start + tcp_data_length;
1587 	/* error checking - better not change! */
1588 	if ((thisdir->fin_count > 1) && (thisdir->fin != fin)) {
1589 	    /* it changed, that shouldn't happen! */
1590 	    if (warn_printbad_syn_fin_seq)
1591 		fprintf(stderr, "\
1592 %s->%s: rexmitted FIN had diff. seqnum! (was %lu, now %lu, etime: %d sec)\n",
1593 			thisdir->host_letter,thisdir->ptwin->host_letter,
1594 			thisdir->fin, fin,
1595 			(int)(elapsed(ptp_save->first_time,current_time)/1000000));
1596 	    thisdir->bad_behavior = TRUE;
1597 	}
1598 	thisdir->fin = fin;
1599     }
1600 
1601     /* "ONLY" bug fix - Wed Feb 24, 1999 */
1602     /* the tcp-splicing heuristic needs "windowend", which was only being */
1603     /* calculated BELOW the "only" point below.  Move that part of the */
1604     /* calculation up here! */
1605 
1606     /* remember the OLD window end for graphing */
1607     /* (bug fix - Thu Aug 12, 1999) */
1608     old_this_windowend = thisdir->windowend;
1609 
1610     if (ACK_SET(ptcp)) {
1611 	thisdir->windowend = th_ack + eff_win;
1612     }
1613     /* end bugfix */
1614 
1615 
1616 
1617     /***********************************************************************/
1618     /***********************************************************************/
1619     /* if we're ignoring this connection, do no further processing	   */
1620     /***********************************************************************/
1621     /***********************************************************************/
1622     if (ptp_save->ignore_pair) {
1623 	return(ptp_save);
1624     }
1625 
1626     /* save to a file if requested */
1627     if (output_filename) {
1628 	PcapSavePacket(output_filename,pip,plast);
1629     }
1630 
1631     /* now, print it if requested */
1632     if (printem && !printallofem) {
1633 	printf("Packet %lu\n", pnum);
1634 	printpacket(0,		/* original length not available */
1635 		    (char *)plast - (char *)pip + 1,
1636 		    NULL,0,	/* physical stuff not known here */
1637 		    pip,plast,thisdir);
1638     }
1639 
1640     /* grab the address from this packet */
1641     CopyAddr(&tp_in.addr_pair, pip,
1642 	     th_sport, th_dport);
1643 
1644 
1645     /* simple bookkeeping */
1646     if (PIP_ISV6(pip)) {
1647 	++thisdir->ipv6_segments;
1648     }
1649 
1650 
1651     /* plotter shorthand */
1652     to_tsgpl     = otherdir->tsg_plotter;
1653     from_tsgpl   = thisdir->tsg_plotter;
1654 
1655     /* plotter shorthand (NOTE: we are using one plotter for both directions) */
1656     tlinepl      = thisdir->tline_plotter;
1657 
1658     /* check the options */
1659     ptcpo = ParseOptions(ptcp,plast);
1660     if (ptcpo->mss != -1)
1661 	thisdir->mss = ptcpo->mss;
1662     if (ptcpo->ws != -1) {
1663 	thisdir->window_scale = ptcpo->ws;
1664 	thisdir->f1323_ws = TRUE;
1665     }
1666     if (ptcpo->tsval != -1) {
1667 	thisdir->f1323_ts = TRUE;
1668     }
1669     /* NOW, unless BOTH sides asked for window scaling in their SYN	*/
1670     /* segments, we aren't using window scaling */
1671     if (!SYN_SET(ptcp) &&
1672 	((!thisdir->f1323_ws) || (!otherdir->f1323_ws))) {
1673 	thisdir->window_scale = otherdir->window_scale = 0;
1674     }
1675 
1676     /* check sacks */
1677     if (ptcpo->sack_req) {
1678 	thisdir->fsack_req = 1;
1679     }
1680     if (ptcpo->sack_count > 0) {
1681 	++thisdir->sacks_sent;
1682     }
1683 
1684     /* unless both sides advertised sack, we shouldn't see them, otherwise
1685        we hope they actually send them */
1686     if (!SYN_SET(ptcp) && (thisdir->fsack_req && otherdir->fsack_req)) {
1687 	thisdir->tcp_strain = otherdir->tcp_strain = TCP_SACK;
1688     }
1689 
1690     /* do data stats */
1691     urg = FALSE;
1692     if (tcp_data_length > 0) {
1693 	thisdir->data_pkts += 1;
1694 	if (PUSH_SET(ptcp))
1695 	    thisdir->data_pkts_push += 1;
1696 	thisdir->data_bytes += tcp_data_length;
1697         if (URGENT_SET(ptcp)) {     /* Checking if URGENT bit is set */
1698 	    urg = TRUE;
1699 	    thisdir->urg_data_pkts += 1;
1700 	    thisdir->urg_data_bytes += th_urp;
1701 	}
1702        	if (tcp_data_length > thisdir->max_seg_size)
1703 	    thisdir->max_seg_size = tcp_data_length;
1704 	if ((thisdir->min_seg_size == 0) ||
1705 	    (tcp_data_length < thisdir->min_seg_size))
1706 	    thisdir->min_seg_size = tcp_data_length;
1707 	/* record first and last times for data (Mallman) */
1708 	if (ZERO_TIME(&thisdir->first_data_time))
1709 	    thisdir->first_data_time = current_time;
1710 	thisdir->last_data_time = current_time;
1711     }
1712 
1713     /* total packets stats */
1714     ++ptp_save->packets;
1715     ++thisdir->packets;
1716 
1717     /* If we are using window scaling, update the win_scaled_pkts counter */
1718     if (thisdir->window_stats_updated_for_scaling)
1719 	++thisdir->win_scaled_pkts;
1720 
1721     /* instantaneous throughput stats */
1722     if (graph_tput) {
1723 	DoThru(thisdir,tcp_data_length);
1724     }
1725 
1726     /* segment size graphs */
1727     if ((tcp_data_length > 0) && (thisdir->segsize_plotter != NO_PLOTTER)) {
1728 	extend_line(thisdir->segsize_line, current_time, tcp_data_length);
1729 	extend_line(thisdir->segsize_avg_line, current_time,
1730 		    thisdir->data_bytes / thisdir->data_pkts);
1731     }
1732 
1733     /* sequence number stats */
1734     if ((thisdir->min_seq == 0) && (start != 0)) {
1735 	thisdir->min_seq = start; /* first byte in this segment */
1736 	thisdir->max_seq = end;	  /* last byte in this segment */
1737     }
1738     if (SEQ_GREATERTHAN (end,thisdir->max_seq)) {
1739 	thisdir->max_seq = end;
1740     }
1741     thisdir->latest_seq = end;
1742 
1743 
1744     /* check for hardware duplicates */
1745     /* only works for IPv4, IPv6 has no mandatory ID field */
1746     if (PIP_ISV4(pip) && docheck_hw_dups)
1747 	hw_dup = check_hw_dups(pip->ip_id, th_seq, thisdir);
1748 
1749 
1750     /* Kevin Lahey's ECN code */
1751     /* only works for IPv4 */
1752     if (PIP_ISV4(pip)) {
1753 	ecn_ce = IP_ECT(pip) && IP_CE(pip);
1754     }
1755     cwr = CWR_SET(ptcp);
1756     ecn_echo = ECN_ECHO_SET(ptcp);
1757 
1758     /* save the stream contents, if requested */
1759     if (tcp_data_length > 0) {
1760 	u_char *pdata = (u_char *)ptcp + TH_OFF(ptcp)*4;
1761 	u_long saved;
1762 	u_long	missing;
1763 
1764 	saved = tcp_data_length;
1765 	if ((char *)pdata + tcp_data_length > ((char *)plast+1))
1766 	    saved = (char *)plast - (char *)pdata + 1;
1767 
1768 	/* see what's missing */
1769 	missing = tcp_data_length - saved;
1770 	if (missing > 0) {
1771 	    thisdir->trunc_bytes += missing;
1772 	    ++thisdir->trunc_segs;
1773 	}
1774 
1775 	if (save_tcp_data)
1776 	    ExtractContents(start,tcp_data_length,saved,pdata,thisdir);
1777     }
1778 
1779     /* do rexmit stats */
1780     retrans = FALSE;
1781     probe = FALSE;
1782     out_order = FALSE;
1783     retrans_num_bytes = 0;
1784     if (SYN_SET(ptcp) || FIN_SET(ptcp) || tcp_data_length > 0) {
1785 	int len = tcp_data_length;
1786 	int retrans_cnt=0;
1787 
1788 	if (SYN_SET(ptcp)) ++len;
1789 	if (FIN_SET(ptcp)) ++len;
1790 
1791 
1792 	/* Don't consider for rexmit, if the send window is 0 */
1793 	/* We are probably doing window probing.. */
1794 	/* Patch from Ulisses Alonso Camaro : Not treat the SYN segments
1795 	 * as probes, even though a zero window was advertised from the
1796 	 * opposite direction */
1797 	if( (otherdir->win_last==0) && (otherdir->packets > 0) &&
1798 	   /* Patch from Ulisses Alonso Camaro : Not treat the SYN segments
1799 	    * as probes, even though a zero window was advertised from the
1800 	    * opposite direction */
1801             (!SYN_SET(ptcp)) ) {
1802 		probe=TRUE;
1803 		thisdir->num_zwnd_probes++;
1804 		thisdir->zwnd_probe_bytes += tcp_data_length;
1805 	}
1806 	else
1807 		retrans_cnt = retrans_num_bytes = rexmit(thisdir,start, len, &out_order);
1808 
1809 	if (out_order)
1810 	    ++thisdir->out_order_pkts;
1811 
1812 	/* count anything NOT retransmitted as "unique" */
1813 	/* exclude SYN and FIN */
1814 	if (SYN_SET(ptcp)) {
1815 	    /* don't count the SYN as data */
1816 	    --len;
1817 	    /* if the SYN was rexmitted, then don't count it */
1818 	    if (thisdir->syn_count > 1)
1819 		--retrans_cnt;
1820 	}
1821 	if (FIN_SET(ptcp)) {
1822 	    /* don't count the FIN as data */
1823 	    --len;
1824 	    /* if the FIN was rexmitted, then don't count it */
1825 	    if (thisdir->fin_count > 1)
1826 		--retrans_cnt;
1827 	}
1828 	if (!probe){
1829 		if(retrans_cnt < len)
1830 	    	thisdir->unique_bytes += (len - retrans_cnt);
1831 	    }
1832     }
1833 
1834 
1835     /* do rtt stats */
1836     if (ACK_SET(ptcp)) {
1837 	ack_type = ack_in(otherdir,th_ack,tcp_data_length,eff_win,0);
1838 
1839 #ifdef EXPERIMENTAL_ONLY
1840 	/* check first SACK block too to see if there's good rtt info in it */
1841 	if (ptcpo->sack_count > 0) {
1842 	    tcp_seq sack = ptcpo->sacks[0].sack_right;
1843 	    if (sack > th_ack) {
1844 		/* NOT a dsack, so this is ACKing new data */
1845 		(void) ack_in(otherdir,sack,tcp_data_length,eff_win,1);
1846 	    }
1847 	}
1848 #endif
1849 
1850 
1851 	if ( (th_ack == (otherdir->syn+1)) &&
1852 		 (otherdir->syn_count == 1) )
1853 		 otherdir->rtt_3WHS=otherdir->rtt_last;
1854 		 /* otherdir->rtt_last was set in the call to ack_in() */
1855 
1856         otherdir->lastackno = th_ack;
1857     }
1858 
1859     /* LEAST */
1860     if (thisdir->tcp_strain == TCP_RENO) {
1861       if (thisdir->in_rto && tcp_data_length > 0) {
1862         if (retrans_num_bytes>0 && th_seq < thisdir->recovered)
1863           thisdir->event_retrans++;
1864         if (IsRTO(thisdir, th_seq)) {
1865           thisdir->recovered = thisdir->recovered_orig = thisdir->seq;
1866           thisdir->rto_segment = th_seq;
1867         }
1868         if (!(retrans_num_bytes>0) && thisdir->ack <= thisdir->recovered_orig)
1869           thisdir->recovered = th_seq;
1870       }
1871       if (otherdir->in_rto && ACK_SET(ptcp)) {
1872         if (th_ack > otherdir->recovered) {
1873           otherdir->LEAST -=
1874             (otherdir->event_dupacks < otherdir->event_retrans)?
1875              otherdir->event_dupacks:otherdir->event_retrans;
1876           otherdir->in_rto = FALSE;
1877         } else if (th_ack == otherdir->lastackno &&
1878                    th_ack >= otherdir->rto_segment) otherdir->event_dupacks++;
1879       }
1880     }
1881 
1882     /* plot out-of-order segments, if asked */
1883     if (out_order && (from_tsgpl != NO_PLOTTER) && show_out_order) {
1884 	plotter_perm_color(from_tsgpl, out_order_color);
1885 	plotter_text(from_tsgpl, current_time, SeqRep(thisdir,end),
1886 		     "a", "O");
1887 	if (bottom_letters)
1888 	    plotter_text(from_tsgpl, current_time,
1889 			 SeqRep(thisdir,thisdir->min_seq)-1500,
1890 			 "c", "O");
1891     }
1892 
1893     /* stats for rexmitted data */
1894     if (retrans_num_bytes>0) {
1895 	retrans = TRUE;
1896         /* for reno LEAST estimate */
1897         if (thisdir->tcp_strain == TCP_RENO &&
1898             !thisdir->in_rto && IsRTO(thisdir, th_seq)) {
1899           thisdir->in_rto = TRUE;
1900           thisdir->recovered = thisdir->recovered_orig = thisdir->seq;
1901           thisdir->rto_segment = th_seq;
1902           thisdir->event_retrans = 1; thisdir->event_dupacks = 0;
1903         }
1904 	thisdir->rexmit_pkts += 1;
1905 	thisdir->LEAST++;
1906 	thisdir->rexmit_bytes += retrans_num_bytes;
1907 	/* don't color the SYNs and FINs, it's confusing, we'll do them */
1908 	/* differently below... */
1909 	if (!(FIN_SET(ptcp)||SYN_SET(ptcp)) &&
1910 	    from_tsgpl != NO_PLOTTER && show_rexmit) {
1911 	    plotter_perm_color(from_tsgpl, retrans_color);
1912 	    plotter_text(from_tsgpl, current_time, SeqRep(thisdir,end),
1913 			 "a", hw_dup?"HD":"R");
1914 	    if (bottom_letters)
1915 		plotter_text(from_tsgpl, current_time,
1916 			     SeqRep(thisdir,thisdir->min_seq)-1500,
1917 			     "c", hw_dup?"HD":"R");
1918 	}
1919     } else {
1920 	thisdir->seq = end;
1921     }
1922 
1923     if(probe) {
1924         if(from_tsgpl != NO_PLOTTER && show_zwnd_probes){
1925 	    plotter_perm_color(from_tsgpl,probe_color);
1926 	    plotter_text(from_tsgpl,current_time,SeqRep (thisdir,end),
1927 			  "b", "P");
1928 	 }
1929      }
1930 
1931     /* draw the packet */
1932     if (from_tsgpl != NO_PLOTTER) {
1933 	plotter_perm_color(from_tsgpl, data_color);
1934 	if (SYN_SET(ptcp)) {		/* SYN  */
1935 	    /* if we're using time offsets from zero, it's easier if */
1936 	    /* both graphs (a2b and b2a) start at the same point.  That */
1937 	    /* will only happen if the "left-most" graphic is in the */
1938 	    /* same place in both.  To make sure, mark the SYNs */
1939 	    /* as a green dot in the other direction */
1940 	    if (ACK_SET(ptcp)) {
1941 		plotter_temp_color(from_tsgpl, ack_color);
1942 		plotter_dot(from_tsgpl,
1943 			    ptp_save->first_time, SeqRep(thisdir,start));
1944 	    }
1945 	    plotter_perm_color(from_tsgpl,
1946 			       hw_dup?hw_dup_color:
1947 			       retrans_num_bytes>0?retrans_color:
1948 			       synfin_color);
1949 	    plotter_diamond(from_tsgpl, current_time, SeqRep(thisdir,start));
1950 	    plotter_text(from_tsgpl, current_time,
1951 			 SeqRep(thisdir,start+1), "a",
1952 			 hw_dup?"HD SYN":
1953 			 retrans_num_bytes>0?"R SYN":
1954 			 "SYN");
1955 	    plotter_uarrow(from_tsgpl, current_time, SeqRep(thisdir,start+1));
1956 	    plotter_line(from_tsgpl,
1957 			 current_time, SeqRep(thisdir,start),
1958 			 current_time, SeqRep(thisdir,start+1));
1959 	} else if (FIN_SET(ptcp)) {	/* FIN  */
1960 	   /* Wed Sep 18, 2002 - bugfix
1961 	    * Check if data is present in the last packet.
1962 	    * We will draw the data bytes with the normal color
1963 	    * and then change the color for the last byte of FIN.
1964 	    */
1965 	    if(tcp_data_length > 0) { /* DATA + FIN */
1966 	       /* Data - default color */
1967 	       plotter_darrow(from_tsgpl, current_time, SeqRep(thisdir,start));
1968 	       plotter_line(from_tsgpl,
1969 			    current_time, SeqRep(thisdir,start),
1970 			    current_time, SeqRep(thisdir,end));
1971 	       /* FIN - synfin color */
1972 	       plotter_perm_color(from_tsgpl,
1973 				  hw_dup?hw_dup_color:
1974 				  retrans_num_bytes>0?retrans_color:
1975 				  synfin_color);
1976 	    }
1977 	    else { /* Only FIN */
1978 	       /* FIN - synfin color */
1979 	       plotter_perm_color(from_tsgpl,
1980 				  hw_dup?hw_dup_color:
1981 				  retrans_num_bytes>0?retrans_color:
1982 				  synfin_color);
1983 	       plotter_darrow(from_tsgpl, current_time, SeqRep(thisdir,end));
1984 	    }
1985 	    plotter_line(from_tsgpl,
1986 			 current_time, SeqRep(thisdir,end),
1987 			 current_time, SeqRep(thisdir,end+1));
1988 	    plotter_box(from_tsgpl, current_time, SeqRep(thisdir,end+1));
1989 	    plotter_text(from_tsgpl, current_time,
1990 			 SeqRep(thisdir,end+1), "a",
1991 			 hw_dup?"HD FIN":
1992 			 retrans_num_bytes>0?"R FIN":
1993 			 "FIN");
1994 
1995 	} else if (tcp_data_length > 0) {		/* DATA */
1996 	    if (hw_dup) {
1997 		plotter_perm_color(from_tsgpl, hw_dup_color);
1998 	    } else if (retrans) {
1999 		plotter_perm_color(from_tsgpl, retrans_color);
2000 	    }
2001 	    plotter_darrow(from_tsgpl, current_time, SeqRep(thisdir,start));
2002 	    if (PUSH_SET(ptcp)) {
2003 		/* colored diamond is PUSH */
2004 		plotter_temp_color(from_tsgpl, push_color);
2005 		plotter_diamond(from_tsgpl,
2006 				current_time, SeqRep(thisdir,end));
2007 		plotter_temp_color(from_tsgpl, push_color);
2008 		plotter_dot(from_tsgpl, current_time, SeqRep(thisdir,end));
2009 	    } else {
2010 		plotter_uarrow(from_tsgpl, current_time, SeqRep(thisdir,end));
2011 	    }
2012 	    plotter_line(from_tsgpl,
2013 			 current_time, SeqRep(thisdir,start),
2014 			 current_time, SeqRep(thisdir,end));
2015 	} else if (tcp_data_length == 0) {
2016 	    /* for Brian Utterback */
2017 	    if (graph_zero_len_pkts) {
2018 		/* draw zero-length packets */
2019 		/* shows up as an X, really two arrow heads */
2020 		plotter_darrow(from_tsgpl,
2021 			       current_time, SeqRep(thisdir,start));
2022 		plotter_uarrow(from_tsgpl,
2023 			       current_time, SeqRep(thisdir,start));
2024 	    }
2025 	}
2026 
2027 	/* Kevin Lahey's code */
2028 	/* XXX:  can this overwrite other labels!? */
2029 	if (cwr || ecn_ce) {
2030 	    plotter_perm_color(from_tsgpl, ecn_color);
2031 	    plotter_diamond(from_tsgpl,
2032 			    current_time, SeqRep(thisdir,start));
2033 	    plotter_text(from_tsgpl, current_time, SeqRep(thisdir, start), "a",
2034 			 cwr ? (ecn_ce ? "CWR CE" : "CWR") : "CE");
2035 	}
2036 
2037     }
2038 
2039     /* Plotting URGENT data */
2040     if(urg) {
2041         if(from_tsgpl != NO_PLOTTER && show_urg){
2042 	    plotter_perm_color(from_tsgpl,urg_color);
2043 	    plotter_text(from_tsgpl,current_time,SeqRep (thisdir,end),
2044 			   "a", "U");
2045 	 }
2046     }
2047 
2048    /* graph time line */
2049    /* Since the axis types have been switched specially for these graphs,
2050     * x is actually used as y and y as x
2051     * -Avinash.
2052     *
2053     * NOTE: This code is lacking about a 1000 lines of intellegence that is needed
2054     * ----- to draw these graphs correctly. I have left it in here as the starting
2055     *       point to work on. Whoever is working on this project would want to clean
2056     *       up this file trace.c (based on the patches in the README.tline_graphs
2057     *       file), and continue development as a seperate module. We started this
2058     *       project thinking it is easy to draw these graphs, and then realized that
2059     *       it is infact quite a complicated task. All this works with a -L option at
2060     *       command line.
2061     */
2062    if (tlinepl != NO_PLOTTER) {
2063       char buf1[200];
2064       char buf2[50];
2065       static seqnum a2b_first_seqnum = 0;
2066       static seqnum b2a_first_seqnum = 0;
2067       /* 1/3rd rtt. Since we have the timestamps only on one side, we calculate the
2068        * arrrival/departure time of the segments on the other side by adding/subtracting
2069        * 1/3rd rtt. We assume that it takes 1/3rd time for the segment to travel in
2070        * either direction, and 1/3rd time for processing.
2071        * We also skew the calculated times so that the acks are not seen before the
2072        * segments actually arrive.
2073        */
2074       struct timeval one3rd_rtt;
2075       struct timeval copy_current_time;
2076       /* Make a copy of the current time (Needed for calculations) */
2077       copy_current_time.tv_sec  = current_time.tv_sec;
2078       copy_current_time.tv_usec = current_time.tv_usec;
2079       /* Compute 1/3rd rtt */
2080       one3rd_rtt.tv_sec  = 0;
2081       one3rd_rtt.tv_usec = thisdir->rtt_last/3;
2082       /* Adjust seconds and microseconds */
2083       while(one3rd_rtt.tv_usec >= US_PER_SEC) {
2084 	 one3rd_rtt.tv_usec -= US_PER_SEC;
2085 	 one3rd_rtt.tv_sec += 1;
2086       }
2087 
2088       /* Initializations */
2089       memset(&buf1, 0, sizeof(buf1));
2090       memset(&buf2, 0, sizeof(buf2));
2091 
2092       /* Segment information */
2093       /* Check the flags */
2094       if(SYN_SET(ptcp))
2095 	strncat(buf1, "SYN ", 4);
2096       if(FIN_SET(ptcp))
2097 	strncat(buf1, "FIN ", 4);
2098       if(RESET_SET(ptcp))
2099 	strncat(buf1, "RST ", 4);
2100       if(PUSH_SET(ptcp))
2101 	strncat(buf1, "PSH ", 4);
2102       if(URGENT_SET(ptcp))
2103 	strncat(buf1, "URG ", 4);
2104 
2105 
2106       /* Write the sequence numbers */
2107       if(dir == A2B) {
2108 	 /* Use relative sequence numbers after the first segment in either direction */
2109 	 snprintf(buf2, sizeof(buf2), "%lu:%lu(%lu) ", (start - a2b_first_seqnum),
2110 		  (end - a2b_first_seqnum), (end-start));
2111 	 strncat(buf1, buf2, strlen(buf2));
2112 	 if(a2b_first_seqnum == 0 && !SYN_SET(ptcp)) // Don't use relative sequence numbers until handshake is complete.
2113 	   a2b_first_seqnum = thisdir->min_seq;
2114       }else if(dir == B2A) {
2115 	 /* Use relative sequence numbers after the first segment in either direction */
2116 	 snprintf(buf2, sizeof(buf2), "%lu:%lu(%lu) ", (start - b2a_first_seqnum),
2117 		  (end - b2a_first_seqnum), (end-start));
2118 	 strncat(buf1, buf2, strlen(buf2));
2119 	 if(b2a_first_seqnum == 0 && !SYN_SET(ptcp))
2120 	   b2a_first_seqnum = thisdir->min_seq;
2121       }
2122 
2123       /* Acknowledgements */
2124       if(ACK_SET(ptcp)) {
2125 	 memset(&buf2, 0, sizeof(buf2));
2126 	 if(dir == A2B)
2127 	   snprintf(buf2, sizeof(buf2), "ack %lu ", (th_ack - b2a_first_seqnum));
2128 	 else if(dir == B2A)
2129 	   snprintf(buf2, sizeof(buf2), "ack %lu ", (th_ack - a2b_first_seqnum));
2130 	 strncat(buf1, buf2, strlen(buf2));
2131       }
2132 
2133       /* Advertised Window */
2134 	 memset(&buf2, 0, sizeof(buf2));
2135 	 snprintf(buf2, sizeof(buf2), "win %lu ", eff_win);
2136 	 strncat(buf1, buf2, strlen(buf2));
2137 
2138       /* Retransmits */
2139       if(retrans) {
2140 	 memset(&buf2, 0, sizeof(buf2));
2141 	 snprintf(buf2, sizeof(buf2), "R ");
2142 	 strncat(buf1, buf2, strlen(buf2));
2143       }
2144 
2145       /* Hardware Duplicates */
2146       if(hw_dup) {
2147 	 memset(&buf2, 0, sizeof(buf2));
2148 	 snprintf(buf2, sizeof(buf2), "HD ");
2149 	 strncat(buf1, buf2, strlen(buf2));
2150       }
2151 
2152       /* Draw the segment ------>/<------- */
2153       if(dir == A2B) {
2154 	 tv_add(&copy_current_time, one3rd_rtt);
2155 	 plotter_line(tlinepl, ptp_save->first_time, tline_left, copy_current_time, tline_left);
2156 	 plotter_line(tlinepl, ptp_save->first_time, tline_right, copy_current_time, tline_right);
2157 	 if(SYN_SET(ptcp)|| FIN_SET(ptcp) || RESET_SET(ptcp))
2158 	   plotter_perm_color(tlinepl, synfin_color);
2159 	 else
2160 	   plotter_perm_color(tlinepl, a2b_seg_color);
2161 	 plotter_line(tlinepl, current_time, tline_left, copy_current_time, tline_right);
2162 	 plotter_rarrow(tlinepl, copy_current_time, tline_right);
2163 	 plotter_perm_color(tlinepl, default_color);
2164 	 plotter_text(tlinepl, current_time, tline_left, "l", buf1);
2165       }
2166       else if(dir == B2A) {
2167 	 tv_sub(&copy_current_time, one3rd_rtt);
2168 	 plotter_line(tlinepl, ptp_save->first_time, tline_left, copy_current_time, tline_left);
2169 	 plotter_line(tlinepl, ptp_save->first_time, tline_right, copy_current_time, tline_right);
2170 	 if(SYN_SET(ptcp)|| FIN_SET(ptcp) || RESET_SET(ptcp))
2171 	   plotter_perm_color(tlinepl, synfin_color);
2172 	 else
2173 	   plotter_perm_color(tlinepl, b2a_seg_color);
2174 	 plotter_line(tlinepl, copy_current_time, tline_right, current_time, tline_left);
2175 	 plotter_larrow(tlinepl, current_time, tline_left);
2176 	 plotter_perm_color(tlinepl, default_color);
2177 	 plotter_text(tlinepl, copy_current_time, tline_right, "r", buf1);
2178       }
2179 
2180    }
2181 
2182 
2183     /* check for RESET */
2184     if (RESET_SET(ptcp)) {
2185 	u_long plot_at;
2186 
2187 	/* if there's an ACK in this packet, plot it there */
2188 	/* otherwise, plot it at the last valid ACK we have */
2189 	if (ACK_SET(ptcp))
2190 	    plot_at = th_ack;
2191 	else
2192 	    plot_at = thisdir->ack;
2193 
2194 	if (to_tsgpl != NO_PLOTTER) {
2195 	    plotter_temp_color(to_tsgpl, text_color);
2196 	    plotter_text(to_tsgpl,
2197 			 current_time, SeqRep(otherdir,plot_at),
2198 			 "a", "RST_IN");
2199 	}
2200 	if (from_tsgpl != NO_PLOTTER) {
2201 	    plotter_temp_color(from_tsgpl, text_color);
2202 	    plotter_text(from_tsgpl,
2203 			 current_time, SeqRep(thisdir,start),
2204 			 "a", "RST_OUT");
2205 	}
2206 	if (ACK_SET(ptcp))
2207 	    ++thisdir->ack_pkts;
2208 
2209         if (run_continuously) {
2210             UpdateConnLists(tcp_ptr, ptcp);
2211         }
2212 	return(ptp_save);
2213     }
2214 
2215     /* do window stats (include first SYN too!) */
2216 	thisdir->win_last=eff_win;
2217 
2218     if (ACK_SET(ptcp) || SYN_SET(ptcp)) {
2219 	if (eff_win > thisdir->win_max)
2220 	    thisdir->win_max = eff_win;
2221 
2222 	/* If we *are* going to use window scaling,
2223 	 * i.e., if we saw both SYN segments of the connection requesting
2224 	 * window scaling, we flush out all the window stats we gathered till
2225 	 * now from the SYN segments.
2226 	 *
2227 	 * o We set the flag window_stats_updated_for_scaling to TRUE
2228 	 * o Set win_min and win_max to the value found in this first
2229 	 *   window-scaled segment
2230 	 * o Reset win_tot value too, as this is used to calculate the
2231 	 *   average window advertisement seen in this direction at the end
2232 	 * o We also use the field win_scaled_pkts for this purpose, so that
2233 	 *   in the end we calculate
2234 	 *
2235 	 *   avg_win_adv = win_tot/win_scaled_pkts // Refer output.c
2236 	 *
2237 	 * Note : for a connection that doesn't use window scaling,
2238 	 *
2239 	 *   avg_win_adv = win_tot/packets        // Refer again to output.c
2240 	 */
2241 
2242 	if ( (eff_win>0) &&
2243 	     ( thisdir->f1323_ws && otherdir->f1323_ws && !SYN_SET(ptcp) &&
2244 		!thisdir->window_stats_updated_for_scaling
2245 	     )
2246 	   ) {
2247 	     thisdir->window_stats_updated_for_scaling=TRUE;
2248 	     thisdir->win_min = thisdir->win_max = eff_win;
2249 	     thisdir->win_tot = 0;
2250 	     thisdir->win_scaled_pkts = 1;
2251 	}
2252 	else if ((eff_win > 0) &&
2253 	    ((thisdir->win_min == 0) ||
2254 	     (eff_win < thisdir->win_min)))
2255 	    thisdir->win_min = eff_win;
2256 
2257 	/* Add the window advertisement to win_tot */
2258 	thisdir->win_tot += eff_win;
2259     }
2260 
2261     /* draw the ack and win in the other plotter */
2262     if (ACK_SET(ptcp)) {
2263 	seqnum ack = th_ack;
2264 	u_long winend;
2265 
2266 	winend = ack + eff_win;
2267 
2268 	if (eff_win == 0) {
2269 	    ++thisdir->win_zero_ct;
2270 	    if (to_tsgpl != NO_PLOTTER && show_zero_window) {
2271 		plotter_temp_color(to_tsgpl, text_color);
2272 		plotter_text(to_tsgpl,
2273 			     current_time, SeqRep(otherdir,winend),
2274 			     "a", "Z");
2275 		if (bottom_letters) {
2276 		    plotter_temp_color(to_tsgpl, text_color);
2277 		    plotter_text(to_tsgpl,
2278 				 current_time,
2279 				 SeqRep(otherdir,otherdir->min_seq)-1500,
2280 				 "a", "Z");
2281 		}
2282 	    }
2283 	}
2284 
2285 	++thisdir->ack_pkts;
2286 	if ((tcp_data_length == 0) &&
2287 	    !SYN_SET(ptcp) && !FIN_SET(ptcp) && !RESET_SET(ptcp)) {
2288 	    ++thisdir->pureack_pkts;
2289 	}
2290 
2291 
2292 	if (to_tsgpl != NO_PLOTTER && thisdir->time.tv_sec != -1) {
2293 	    plotter_perm_color(to_tsgpl, ack_color);
2294 	    plotter_line(to_tsgpl,
2295 			 thisdir->time, SeqRep(otherdir,thisdir->ack),
2296 			 current_time, SeqRep(otherdir,thisdir->ack));
2297 	    if (thisdir->ack != ack) {
2298 		plotter_line(to_tsgpl,
2299 			     current_time, SeqRep(otherdir,thisdir->ack),
2300 			     current_time, SeqRep(otherdir,ack));
2301 		if (show_rtt_dongles) {
2302 		    /* draw dongles for "interesting" acks */
2303 		    switch (ack_type) {
2304 		      case NORMAL:	/* normal case */
2305 			/* no dongle */
2306 			break;
2307 		      case CUMUL:	/* cumulative */
2308 			/* won't happen, not plotted here */
2309 			break;
2310 		      case TRIPLE:	/* triple dupacks */
2311 			/* won't happen, not plotted here */
2312 			break;
2313 		      case AMBIG:	/* ambiguous */
2314 			plotter_temp_color(to_tsgpl, ackdongle_ambig_color);
2315 			plotter_diamond(to_tsgpl, current_time,
2316 					SeqRep(otherdir,ack));
2317 			break;
2318 		      case NOSAMP:	/* acks retransmitted stuff cumulatively */
2319 			plotter_temp_color(to_tsgpl, ackdongle_nosample_color);
2320 			plotter_diamond(to_tsgpl, current_time,
2321 					SeqRep(otherdir,ack));
2322 			break;
2323 		    }
2324 		}
2325 	    } else {
2326 		plotter_dtick(to_tsgpl, current_time, SeqRep(otherdir,ack));
2327 		if (show_triple_dupack && (ack_type == TRIPLE)) {
2328 		    plotter_text(to_tsgpl, current_time,
2329 				 SeqRep(otherdir,ack),
2330 				 "a", "3");  /* '3' is for triple dupack */
2331 		}
2332 	    }
2333 
2334 	    /* Kevin Lahey's code */
2335 	    if (ecn_echo && !SYN_SET(ptcp)) {
2336 	        plotter_perm_color(to_tsgpl, ecn_color);
2337 		plotter_diamond(to_tsgpl, current_time, SeqRep(otherdir, ack));
2338 	    }
2339 
2340 	    plotter_perm_color(to_tsgpl, window_color);
2341 	    plotter_line(to_tsgpl,
2342 			 thisdir->time, SeqRep(otherdir,old_this_windowend),
2343 			 current_time, SeqRep(otherdir,old_this_windowend));
2344 	    if (old_this_windowend != winend) {
2345 		plotter_line(to_tsgpl,
2346 			     current_time, SeqRep(otherdir,old_this_windowend),
2347 			     current_time, SeqRep(otherdir,winend));
2348 	    } else {
2349 		plotter_utick(to_tsgpl, current_time, SeqRep(otherdir,winend));
2350 	    }
2351 	}
2352 
2353 	/* track the most sack blocks in a single ack */
2354 	if (ptcpo->sack_count > 0) {
2355 	    ++thisdir->num_sacks;
2356 	    if (ptcpo->sack_count > thisdir->max_sack_blocks)
2357 		thisdir->max_sack_blocks = ptcpo->sack_count;
2358 
2359 	/* also see if any of them are DSACKS - weddy */
2360 	/* eventually may come back and fix this, what if we+++++
2361 	   didn't see all the rexmits and so LEAST wesn't set
2362 	   high enough, now it's too low */
2363 	    /* case 1, first block under cumack */
2364 	    if (ptcpo->sacks[0].sack_right <= th_ack) {
2365 	        thisdir->num_dsacks++;
2366 	        if (otherdir->LEAST > 0) otherdir->LEAST--;
2367 	    /* case 2, first block inside second */
2368 	    } else if (ptcpo->sack_count > 1) {
2369 	        if (ptcpo->sacks[0].sack_right <= ptcpo->sacks[1].sack_right
2370 	            && ptcpo->sacks[0].sack_left >= ptcpo->sacks[1].sack_left)
2371 	        {
2372 	            thisdir->num_dsacks++;
2373 	            if (otherdir->LEAST > 0) otherdir->LEAST--;
2374 	    /* case 3, first and second block overlap */
2375 	        } else if ((ptcpo->sacks[0].sack_left <=
2376 	                    ptcpo->sacks[1].sack_left &&
2377 	                  ptcpo->sacks[0].sack_right >
2378 	                    ptcpo->sacks[1].sack_left) ||
2379                          (ptcpo->sacks[0].sack_right >=
2380 	                    ptcpo->sacks[1].sack_right &&
2381 	                  ptcpo->sacks[0].sack_left <
2382 	                    ptcpo->sacks[1].sack_right)) {
2383                     thisdir->num_dsacks++;
2384 	            if (otherdir->LEAST > 0) otherdir->LEAST--;
2385 	        }
2386 	    }
2387 	    /* if we saw any dsacks from the other guy, we'll assume he did
2388                it on purpose and is a dsack tcp */
2389             if (thisdir->num_dsacks > 0) thisdir->tcp_strain = TCP_DSACK;
2390 	}
2391 
2392 	/* draw sacks, if appropriate */
2393 	if (to_tsgpl != NO_PLOTTER && show_sacks
2394 	    && (ptcpo->sack_count > 0)) {
2395 	    int scount;
2396 	    seqnum sack_top = ptcpo->sacks[0].sack_right;
2397 
2398 	    plotter_perm_color(to_tsgpl, sack_color);
2399 	    for (scount = 0; scount < ptcpo->sack_count; ++scount) {
2400 		plotter_line(to_tsgpl,
2401 			     current_time,
2402 			     SeqRep(otherdir,ptcpo->sacks[scount].sack_left),
2403 			     current_time,
2404 			     SeqRep(otherdir,ptcpo->sacks[scount].sack_right));
2405 		/* make it easier to read multiple sacks by making them look like
2406 		   |-----|  (sideways)
2407 		*/
2408 		plotter_htick(to_tsgpl,
2409 			      current_time,
2410 			      SeqRep(otherdir,ptcpo->sacks[scount].sack_left));
2411 		plotter_htick(to_tsgpl,
2412 			      current_time,
2413 			      SeqRep(otherdir,ptcpo->sacks[scount].sack_right));
2414 
2415 		/* if there's more than one, label the order */
2416 		/* purple number to the right of the top ("right" edge) */
2417 		if (ptcpo->sack_count > 1) {
2418 		    char buf[5]; /* can't be more than 1 digit! */
2419 		    snprintf(buf,sizeof(buf),"%u",scount+1);	/* 1-base, rather than 0-base */
2420 		    plotter_text(to_tsgpl,
2421 				 current_time,
2422 				 SeqRep(otherdir,ptcpo->sacks[scount].sack_right),
2423 				 "r", buf);
2424 		}
2425 
2426 		/* maintain the highest SACK so we can label them all at once */
2427 		if (SEQ_GREATERTHAN(ptcpo->sacks[scount].sack_right, sack_top))
2428 		    sack_top = ptcpo->sacks[scount].sack_right;
2429 	    }
2430 	    /* change - just draw the 'S' above the highest one */
2431 	    plotter_text(to_tsgpl, current_time,
2432 			 SeqRep(otherdir,sack_top),
2433 			 "a", "S");  /* 'S' is for Sack */
2434 	}
2435 	thisdir->time = current_time;
2436 	thisdir->ack = ack;
2437 
2438 /* 	thisdir->windowend = winend;  (moved above "only" point) */
2439     }  /* end ACK_SET(ptcp) */
2440 
2441     /* do stats for initial window (first slow start) */
2442     /* (if there's data in this and we've NEVER seen */
2443     /*  an ACK coming back from the other side) */
2444     /* this is for Mark Allman for slow start testing -- Mon Mar 10, 1997 */
2445     if (!otherdir->data_acked && ACK_SET(ptcp)
2446 	&& ((otherdir->syn+1) != th_ack)) {
2447 	otherdir->data_acked = TRUE;
2448     }
2449     if ((tcp_data_length > 0) && (!thisdir->data_acked)) {
2450 	if (!retrans) {
2451 	    /* don't count it if it was retransmitted */
2452 	    thisdir->initialwin_bytes += tcp_data_length;
2453 	    thisdir->initialwin_segs += 1;
2454 	}
2455     }
2456 
2457     /* do stats for congestion window (estimated) */
2458     /* estimate the congestion window as the number of outstanding */
2459     /* un-acked bytes */
2460     if (!SYN_SET(ptcp) && !out_order && !retrans) {
2461 	u_long owin;
2462 	/* If there has been no ack from the other direction, owin is just
2463 	 * bytes in this pkt.
2464 	 */
2465 	if (otherdir->ack == 0){
2466 		owin = end - start ;
2467 	}
2468 	else {
2469 		/* ack  always acks 'received + 1' bytes, so subtract 1
2470 		 * for owin */
2471 		owin = end - (otherdir->ack - 1);
2472 	}
2473 
2474 	if (owin > thisdir->owin_max)
2475 	    thisdir->owin_max = owin;
2476 	if ((owin > 0) &&
2477 	    ((thisdir->owin_min == 0) ||
2478 	     (owin < thisdir->owin_min)))
2479 	    thisdir->owin_min = owin;
2480 
2481 	thisdir->owin_tot += owin;
2482        	thisdir->owin_count++;
2483 
2484 	/* adding mark's suggestion of weighted owin */
2485 	if (thisdir->previous_owin_sample_time.tv_sec == 0) {
2486 	  /* if this is first ever sample for thisdir */
2487 		thisdir->previous_owin_sample_time = thisdir->last_time;
2488 		thisdir->previous_owin_sample = owin;
2489 	}
2490 	else {
2491 		/* weight each owin sample with the duration that it exists for */
2492         	sample_elapsed_time = (elapsed(thisdir->previous_owin_sample_time, ptp_save->last_time))/1000000;
2493         	total_elapsed_time = (elapsed(ptp_save->first_time, ptp_save->last_time))/1000000;
2494 		thisdir->owin_wavg += (u_llong)((thisdir->previous_owin_sample) * sample_elapsed_time);
2495 		/* graph owin_wavg */
2496 		if (thisdir->owin_plotter != NO_PLOTTER) {
2497 			extend_line(thisdir->owin_wavg_line, thisdir->previous_owin_sample_time,
2498 		        	(total_elapsed_time)?((u_llong)((thisdir->owin_wavg)/total_elapsed_time)):0);
2499 		}
2500 	    	thisdir->previous_owin_sample_time = thisdir->last_time;
2501 		thisdir->previous_owin_sample = owin;
2502 	}
2503 
2504 	/* graph owin */
2505 	if (thisdir->owin_plotter != NO_PLOTTER) {
2506 	    extend_line(thisdir->owin_line, current_time, owin);
2507 	    if (show_rwinline) {
2508 	      extend_line(thisdir->rwin_line, current_time,
2509 			  otherdir->win_last);
2510 	    }
2511 	    extend_line(thisdir->owin_avg_line, current_time,
2512 			(thisdir->owin_count?(thisdir->owin_tot/thisdir->owin_count):0));
2513 	}
2514 
2515 	/* add to rwin graph */
2516 	if (thisdir->recvwin_plotter != NO_PLOTTER) {
2517 	    extend_line(thisdir->recvwin_line, current_time, otherdir->win_last);
2518 	}
2519 
2520     }
2521     if (run_continuously) {
2522       UpdateConnLists(tcp_ptr, ptcp);
2523     }
2524 
2525     return(ptp_save);
2526 }
2527 
2528 
2529 
2530 void
trace_done(void)2531 trace_done(void)
2532 {
2533   tcp_pair *ptp;
2534   FILE *f_passfilter = NULL;
2535   int ix;
2536   static int count = 0;
2537   Bool incomplete_pkt_capture = FALSE;
2538 
2539   if (!run_continuously) {
2540     if (!printsuppress) {
2541 	if (tcp_trace_count == 0) {
2542 	    fprintf(stdout,"%sno traced TCP packets\n", comment);
2543 	    return;
2544 	} else {
2545 	    fprintf(stdout,"%sTCP connection info:\n", comment);
2546 	}
2547     }
2548 
2549     if (!printbrief)
2550 	fprintf(stdout,"%s%d TCP %s traced:\n",
2551 		comment,
2552 		num_tcp_pairs + 1,
2553 		num_tcp_pairs==0?"connection":"connections");
2554     if (ctrunc > 0) {
2555 	fprintf(stdout,
2556 		"%s*** %lu packets were too short to process at some point\n",
2557 		comment,
2558 		ctrunc);
2559 	if (!warn_printtrunc)
2560 	    fprintf(stdout,"%s\t(use -w option to show details)\n", comment);
2561     }
2562 
2563     /* generate statistics for data storage efficiency */
2564     if (debug>1) {
2565 	int h;
2566 	int occupied_buckets = 0;
2567 	int max_bucket_occupancy = 0;
2568 	int max_searches = 0;
2569 	int max_depth = 0;
2570 	int max_comparisons = 0;
2571 	float max_searches_compare = 0.0;
2572 	fprintf(stdout,"%sTotal searches: %u\n", comment, tcp_packet_count);
2573 	fprintf(stdout,"%s  Total comparisons: %u\n", comment, search_count);
2574 	fprintf(stdout,"%s  Average compares/search: %.2f\n",
2575 		comment, (float)search_count / (float)tcp_packet_count);
2576 	fprintf(stdout,"%sHash table size: %u\n", comment, HASH_TABLE_SIZE);
2577 	for (h=0; h < HASH_TABLE_SIZE; ++h) {
2578 	    struct search_efficiency *pse = &hashtable_efficiency[h];
2579 	    float searches_compare;
2580 	    if (pse->num_connections > 0)
2581 		++occupied_buckets;
2582 	    if (pse->max_connections > max_bucket_occupancy)
2583 		max_bucket_occupancy = pse->max_connections;
2584 	    if (pse->num_searches > max_searches)
2585 		max_searches = pse->num_searches;
2586 	    if (pse->num_comparisons > max_comparisons)
2587 		max_comparisons = pse->num_comparisons;
2588 	    if (pse->max_depth > max_depth)
2589 		max_depth = pse->max_depth;
2590 	    searches_compare = (float) pse->num_comparisons / (float) pse->num_searches;
2591 	    if (searches_compare > max_searches_compare)
2592 		max_searches_compare = searches_compare;
2593 	}
2594 	fprintf(stdout,"%s    Occupied hash buckets: %u\n", comment, occupied_buckets);
2595 	fprintf(stdout,"%s    Max entries/bucket: %u\n", comment, max_bucket_occupancy);
2596 	fprintf(stdout,"%s    Max searches/bucket: %u\n", comment, max_searches);
2597 	fprintf(stdout,"%s    Max comparisons/bucket: %u\n", comment, max_comparisons);
2598 	fprintf(stdout,"%s    Max avg compares/search: %.2f\n", comment, max_searches_compare);
2599 	fprintf(stdout,"%s    Max tree depth: %u\n", comment, max_depth);
2600     }
2601 
2602     /* complete the "idle time" calculations using NOW */
2603     for (ix = 0; ix <= num_tcp_pairs; ++ix) {
2604 	tcp_pair *ptp = ttp[ix];
2605 	tcb *thisdir;
2606 	u_llong itime;
2607 
2608 	/* if it's CLOSED, skip it */
2609 	if ((FinCount(ptp)>=2) || (ConnReset(ptp)))
2610 	    continue;
2611 
2612 	/* a2b direction */
2613 	thisdir = &ptp->a2b;
2614 	if (!ZERO_TIME(&thisdir->last_time)) {
2615 	    itime = elapsed(thisdir->last_time,current_time);
2616 	    if (itime > thisdir->idle_max)
2617 		thisdir->idle_max = itime;
2618 	}
2619 
2620 
2621 	/* b2a direction */
2622 	thisdir = &ptp->b2a;
2623 	if (!ZERO_TIME(&thisdir->last_time)) {
2624 	    itime = elapsed(thisdir->last_time,current_time);
2625 	    if (itime > thisdir->idle_max)
2626 		thisdir->idle_max = itime;
2627 	}
2628     }
2629   }
2630 
2631     /* if we're filtering, see which connections pass */
2632     if (filter_output || ignore_non_comp) {
2633 
2634 	/* file to dump matching connection numbers into */
2635 	f_passfilter = fopen(PASS_FILTER_FILENAME,"w+");
2636 	if (f_passfilter == NULL) {
2637 	    perror(PASS_FILTER_FILENAME);
2638 	    exit(-1);
2639 	}
2640 
2641       if (filter_output) {
2642 	 if (!run_continuously) {
2643 	    /* mark the connections to ignore */
2644 	    for (ix = 0; ix <= num_tcp_pairs; ++ix) {
2645 	       ptp = ttp[ix];
2646 	       if (PassesFilter(ptp)) {
2647 		  if (++count == 1)
2648 		      fprintf(f_passfilter,"%d", ix+1);
2649 		  else
2650 		      fprintf(f_passfilter,",%d", ix+1);
2651 	       } else {
2652 		  /* else ignore it */
2653 		  ptp->ignore_pair = TRUE;
2654 	       }
2655 	    }
2656 	 }
2657       }
2658     }
2659 
2660   if (!run_continuously) {
2661     /* print each connection */
2662     if (!printsuppress) {
2663         Bool first = TRUE; /* Used with <SP>-separated-values
2664 			    * Keeps track of whether header has already
2665 			    * been printed */
2666 	for (ix = 0; ix <= num_tcp_pairs; ++ix) {
2667 	    ptp = ttp[ix];
2668 
2669 	    if (!ptp->ignore_pair) {
2670 		if ((printbrief) && (!ignore_non_comp || ConnComplete(ptp))) {
2671 		    fprintf(stdout,"%3d: ", ix+1);
2672 		    PrintBrief(ptp);
2673 		} else if (!ignore_non_comp || ConnComplete(ptp)) {
2674 		    if(csv || tsv || (sv != NULL)) {
2675 		       if(first) {
2676 			  PrintSVHeader();
2677 			  first = FALSE;
2678 		       }
2679 		       fprintf(stdout, "%d%s", ix+1, sp);
2680 		    }
2681 		    else {
2682 		       if (ix > 0)
2683 			 fprintf(stdout,"================================\n");
2684 		       fprintf(stdout,"TCP connection %d:\n", ix+1);
2685 
2686 		    }
2687 		    PrintTrace(ptp);
2688 		}
2689 	       /* This piece of code dumps PF file when filtered with '-c'
2690 		  option, this option says to select only complete connections.
2691 		  The PF file will contain the connection numbers which are
2692 		  selected to be complete */
2693 	       if (ignore_non_comp)
2694 		   if (ConnComplete(ptp)) {
2695 		      if (++count == 1)
2696 			  fprintf(f_passfilter, "%d", ix+1);
2697 		      else
2698 			  fprintf(f_passfilter, ",%d", ix+1);
2699 		   }
2700 	       /******************************/
2701 
2702 	      /* If we are extracting packet contents (-e option), we shall check to
2703 	       * see if we missed segments during packet capture causing the
2704 	       * X2Y_contents.dat files that we drop to contain voids in them.
2705 	       * We shall emit a warning upon such an event below. */
2706 	      if (save_tcp_data && !incomplete_pkt_capture && MissingData(ptp))
2707 		incomplete_pkt_capture = TRUE;
2708 	    }
2709 	}
2710     }
2711   }
2712 
2713     /* if we're filtering, close the file */
2714     if (filter_output || ignore_non_comp) {
2715 	fprintf(f_passfilter,"\n");
2716 	fclose(f_passfilter);
2717     }
2718 
2719     if (incomplete_pkt_capture) {
2720       fprintf(stderr, "\nWarning : some extracted files are incomplete!\n");
2721       fprintf(stderr, "          Please see -l output for more detail.\n");
2722     }
2723 
2724     if ((debug>2) && !nonames)
2725 	cadump();
2726 }
2727 
2728 static void
MoreTcpPairs(int num_needed)2729 MoreTcpPairs(
2730     int num_needed)
2731 {
2732     int new_max_tcp_pairs;
2733     int i;
2734 
2735     if (num_needed < max_tcp_pairs)
2736 	return;
2737 
2738     new_max_tcp_pairs = max_tcp_pairs * 4;
2739     while (new_max_tcp_pairs < num_needed)
2740 	new_max_tcp_pairs *= 4;
2741 
2742     if (debug)
2743 	printf("trace: making more space for %d total TCP pairs\n",
2744 	       new_max_tcp_pairs);
2745 
2746     /* enlarge array to hold any pairs that we might create */
2747     ttp = ReallocZ(ttp,
2748 		   max_tcp_pairs * sizeof(tcp_pair *),
2749 		   new_max_tcp_pairs * sizeof(tcp_pair *));
2750 
2751     /* enlarge array to keep track of which ones to ignore */
2752     ignore_pairs = ReallocZ(ignore_pairs,
2753 			    max_tcp_pairs * sizeof(Bool),
2754 			    new_max_tcp_pairs * sizeof(Bool));
2755     if (more_conns_ignored)
2756 	for (i=max_tcp_pairs; i < new_max_tcp_pairs;++i)
2757 	    ignore_pairs[i] = TRUE;
2758 
2759     max_tcp_pairs = new_max_tcp_pairs;
2760 }
2761 
2762 
2763 void
trace_init(void)2764 trace_init(void)
2765 {
2766     static Bool initted = FALSE;
2767 
2768     if (0) {
2769       printf("trace_init called\n");
2770     }
2771 
2772     if (run_continuously) {
2773       if (ignore_pairs) {
2774 	free(ignore_pairs);
2775 	ignore_pairs = NULL;
2776       }
2777       if (ttp) {
2778 	free(ttp);
2779 	ttp = NULL;
2780       }
2781       more_conns_ignored = FALSE;
2782     }
2783 
2784     if (initted)
2785 	return;
2786 
2787     initted = TRUE;
2788 
2789     /* create an array to hold any pairs that we might create */
2790     ttp = (tcp_pair **) MallocZ(max_tcp_pairs * sizeof(tcp_pair *));
2791 
2792     /* create an array to keep track of which ones to ignore */
2793     ignore_pairs = (Bool *) MallocZ(max_tcp_pairs * sizeof(Bool));
2794     if (!run_continuously) {
2795         /* create an array to hold any pairs that we might create */
2796         ttp = (tcp_pair **) MallocZ(max_tcp_pairs * sizeof(tcp_pair *));
2797 
2798         /* create an array to keep track of which ones to ignore */
2799         ignore_pairs = (Bool *) MallocZ(max_tcp_pairs * sizeof(Bool));
2800     }
2801 
2802     cainit();
2803     Minit();
2804 }
2805 
2806 
2807 void
IgnoreConn(int ix)2808 IgnoreConn(
2809     int ix)
2810 {
2811     if (debug) fprintf(stderr,"ignoring conn %d\n", ix);
2812 
2813 //    trace_init();
2814 
2815     --ix;
2816 
2817     MoreTcpPairs(ix);
2818 
2819     more_conns_ignored = FALSE;
2820     ignore_pairs[ix] = TRUE;
2821 }
2822 
2823 
2824 void
OnlyConn(int ix_only)2825 OnlyConn(
2826     int ix_only)
2827 {
2828     int ix;
2829     static Bool cleared = FALSE;
2830 
2831     if (debug) fprintf(stderr,"only printing conn %d\n", ix_only);
2832 
2833 //    trace_init();
2834 
2835     --ix_only;
2836 
2837     MoreTcpPairs(ix_only);
2838 
2839     if (!cleared) {
2840 	for (ix = 0; ix < max_tcp_pairs; ++ix) {
2841 	    ignore_pairs[ix] = TRUE;
2842 	}
2843 	cleared = TRUE;
2844     }
2845 
2846     more_conns_ignored = TRUE;
2847     ignore_pairs[ix_only] = FALSE;
2848 }
2849 
2850 
2851 /* get a long (4 byte) option (to avoid address alignment problems) */
2852 static u_long
get_long_opt(void * ptr)2853 get_long_opt(
2854     void *ptr)
2855 {
2856     u_long l;
2857     memcpy(&l,ptr,sizeof(u_long));
2858     return(l);
2859 }
2860 
2861 
2862 /* get a short (2 byte) option (to avoid address alignment problems) */
2863 static u_short
get_short_opt(void * ptr)2864 get_short_opt(
2865     void *ptr)
2866 {
2867     u_short s;
2868     memcpy(&s,ptr,sizeof(u_short));
2869     return(s);
2870 }
2871 
2872 
2873 struct tcp_options *
ParseOptions(struct tcphdr * ptcp,void * plast)2874 ParseOptions(
2875     struct tcphdr *ptcp,
2876     void *plast)
2877 {
2878     static struct tcp_options tcpo;
2879     struct sack_block *psack;
2880     u_char *pdata;
2881     u_char *popt;
2882     u_char *plen;
2883 
2884     popt  = (u_char *)ptcp + sizeof(struct tcphdr);
2885     pdata = (u_char *)ptcp + TH_OFF(ptcp)*4;
2886 
2887     /* init the options structure */
2888     memset(&tcpo,0,sizeof(tcpo));
2889     tcpo.mss = tcpo.ws = tcpo.tsval = tcpo.tsecr = -1;
2890     tcpo.sack_req = 0;
2891     tcpo.sack_count = -1;
2892     tcpo.echo_req = tcpo.echo_repl = -1;
2893     tcpo.cc = tcpo.ccnew = tcpo.ccecho = -1;
2894 
2895     /* a quick sanity check, the unused (MBZ) bits must BZ! */
2896     if (warn_printbadmbz) {
2897 	if (TH_X2(ptcp) != 0) {
2898 	    fprintf(stderr,
2899 		    "TCP packet %lu: 4 reserved bits are not zero (0x%01x)\n",
2900 		    pnum, TH_X2(ptcp));
2901 	}
2902 	if ((ptcp->th_flags & 0xc0) != 0) {
2903 	    fprintf(stderr,
2904 		    "TCP packet %lu: upper flag bits are not zero (0x%02x)\n",
2905 		    pnum, ptcp->th_flags);
2906 	}
2907     } else {
2908 	static int warned = 0;
2909 	if (!warned &&
2910 	    ((TH_X2(ptcp) != 0) || ((ptcp->th_flags & 0xc0) != 0))) {
2911 	    warned = 1;
2912 	    fprintf(stderr, "\
2913 TCP packet %lu: reserved bits are not all zero.  \n\
2914 \tFurther warnings disabled, use '-w' for more info\n",
2915 		    pnum);
2916 	}
2917     }
2918 
2919     /* looks good, now check each option in turn */
2920     while (popt < pdata) {
2921 	plen = popt+1;
2922 
2923 	/* check for truncation error */
2924 	if ((char *)popt > (char *)plast) {
2925 	    if (warn_printtrunc)
2926 		fprintf(stderr,"\
2927 ParseOptions: packet %lu too short to parse remaining options\n", pnum);
2928 	    ++ctrunc;
2929 	    break;
2930 	}
2931 
2932 #define CHECK_O_LEN(opt) \
2933 	if (*plen == 0) { \
2934 	    if (warn_printtrunc) fprintf(stderr, "\
2935 ParseOptions: packet %lu %s option has length 0, skipping other options\n", \
2936                                            pnum,opt); \
2937 	    popt = pdata; break;} \
2938 	if ((char *)popt + *plen - 1 > (char *)(plast)) { \
2939 	    if (warn_printtrunc) \
2940 		fprintf(stderr, "\
2941 ParseOptions: packet %lu %s option truncated, skipping other options\n", \
2942               pnum,opt); \
2943 	    ++ctrunc; \
2944 	    popt = pdata; break;} \
2945 
2946 
2947 	switch (*popt) {
2948 	  case TCPOPT_EOL: ++popt; break;
2949 	  case TCPOPT_NOP: ++popt; break;
2950 	  case TCPOPT_MAXSEG:
2951 	    CHECK_O_LEN("TCPOPT_MAXSEG");
2952 	    tcpo.mss = ntohs(get_short_opt(popt+2));
2953 	    popt += *plen;
2954 	    break;
2955 	  case TCPOPT_WS:
2956 	    CHECK_O_LEN("TCPOPT_WS");
2957 	    tcpo.ws = *((u_char *)(popt+2));
2958 	    popt += *plen;
2959 	    break;
2960 	  case TCPOPT_TS:
2961 	    CHECK_O_LEN("TCPOPT_TS");
2962 	    tcpo.tsval = ntohl(get_long_opt(popt+2));
2963 	    tcpo.tsecr = ntohl(get_long_opt(popt+6));
2964 	    popt += *plen;
2965 	    break;
2966 	  case TCPOPT_ECHO:
2967 	    CHECK_O_LEN("TCPOPT_ECHO");
2968 	    tcpo.echo_req = ntohl(get_long_opt(popt+2));
2969 	    popt += *plen;
2970 	    break;
2971 	  case TCPOPT_ECHOREPLY:
2972 	    CHECK_O_LEN("TCPOPT_ECHOREPLY");
2973 	    tcpo.echo_repl = ntohl(get_long_opt(popt+2));
2974 	    popt += *plen;
2975 	    break;
2976 	  case TCPOPT_CC:
2977 	    CHECK_O_LEN("TCPOPT_CC");
2978 	    tcpo.cc = ntohl(get_long_opt(popt+2));
2979 	    popt += *plen;
2980 	    break;
2981 	  case TCPOPT_CCNEW:
2982 	    CHECK_O_LEN("TCPOPT_CCNEW");
2983 	    tcpo.ccnew = ntohl(get_long_opt(popt+2));
2984 	    popt += *plen;
2985 	    break;
2986 	  case TCPOPT_CCECHO:
2987 	    CHECK_O_LEN("TCPOPT_CCECHO");
2988 	    tcpo.ccecho = ntohl(get_long_opt(popt+2));
2989 	    popt += *plen;
2990 	    break;
2991 	  case TCPOPT_SACK_PERM:
2992 	    CHECK_O_LEN("TCPOPT_SACK_PERM");
2993 	    tcpo.sack_req = 1;
2994 	    popt += *plen;
2995 	    break;
2996 	  case TCPOPT_SACK:
2997 	    /* see which bytes are acked */
2998 	    CHECK_O_LEN("TCPOPT_SACK");
2999 	    tcpo.sack_count = 0;
3000 	    psack = (sack_block *)(popt+2);  /* past the kind and length */
3001 	    popt += *plen;
3002 	    while ((char *)psack < (char *)popt) {
3003 		struct sack_block *psack_local =
3004 		    &tcpo.sacks[(unsigned)tcpo.sack_count];
3005 		/* warning, possible alignment problem here, so we'll
3006 		   use memcpy() and hope for the best */
3007 		/* better use -fno-builtin to avoid gcc alignment error
3008 		   in GCC 2.7.2 */
3009 		memcpy(psack_local, psack, sizeof(sack_block));
3010 
3011 		/* convert to local byte order (Jamshid Mahdavi) */
3012 		psack_local->sack_left  = ntohl(psack_local->sack_left);
3013 		psack_local->sack_right = ntohl(psack_local->sack_right);
3014 
3015 		++psack;
3016 		if ((char *)psack > ((char *)plast+1)) {
3017 		    /* this SACK block isn't all here */
3018 		    if (warn_printtrunc)
3019 			fprintf(stderr,
3020 				"packet %lu: SACK block truncated\n",
3021 				pnum);
3022 		    ++ctrunc;
3023 		    break;
3024 		}
3025 		++tcpo.sack_count;
3026 		if (tcpo.sack_count > MAX_SACKS) {
3027 		    /* this isn't supposed to be able to happen */
3028 		    fprintf(stderr,
3029 			    "Warning, internal error, too many sacks!!\n");
3030 		    tcpo.sack_count = MAX_SACKS;
3031 		}
3032 	    }
3033 	    break;
3034 	  default:
3035 	    if (debug)
3036 		fprintf(stderr,
3037 			"Warning, ignoring unknown TCP option 0x%x\n",
3038 			*popt);
3039 	    CHECK_O_LEN("TCPOPT_UNKNOWN");
3040 
3041 	    /* record it anyway... */
3042 	    if (tcpo.unknown_count < MAX_UNKNOWN) {
3043 		int ix = tcpo.unknown_count; /* make lint happy */
3044 		tcpo.unknowns[ix].unkn_opt = *popt;
3045 		tcpo.unknowns[ix].unkn_len = *plen;
3046 	    }
3047 	    ++tcpo.unknown_count;
3048 
3049 	    popt += *plen;
3050 	    break;
3051 	}
3052     }
3053 
3054     return(&tcpo);
3055 }
3056 
3057 
3058 
3059 static void
ExtractContents(u_long seq,u_long tcp_data_bytes,u_long saved_data_bytes,void * pdata,tcb * ptcb)3060 ExtractContents(
3061     u_long seq,
3062     u_long tcp_data_bytes,
3063     u_long saved_data_bytes,
3064     void *pdata,
3065     tcb *ptcb)
3066 {
3067     u_long missing;
3068     long offset;
3069     u_long fptr;
3070 	/* Maximum filename could be :
3071 		aaaaaaaa2bbbbbbbb_contents.dat which
3072 		takes 8+1+8+ size of the extension */
3073     static char filename[MAX_HOSTLETTER_LEN
3074 					+1      /* for "2" */
3075 					+MAX_HOSTLETTER_LEN
3076 					+sizeof(CONTENTS_FILE_EXTENSION)
3077 					+1];    /* for terminating NULL. */
3078 
3079     if (debug > 2)
3080 	fprintf(stderr,
3081 		"ExtractContents(seq:%ld  bytes:%ld  saved_bytes:%ld) called\n",
3082 		seq, tcp_data_bytes, saved_data_bytes);
3083 
3084     if (saved_data_bytes == 0)
3085 	return;
3086 
3087     /* how many bytes do we have? */
3088     missing = tcp_data_bytes - saved_data_bytes;
3089     if ((debug > 2) && (missing > 0)) {
3090 	fprintf(stderr,"ExtractContents: missing %ld bytes (%ld-%ld)\n",
3091 		missing,tcp_data_bytes,saved_data_bytes);
3092     }
3093 
3094 
3095     /* if the FILE is "-1", couldn't open file */
3096     if (ptcb->extr_contents_file == (MFILE *) -1) {
3097 	return;
3098     }
3099 
3100     /* if the FILE is NULL, open file */
3101     snprintf(filename,sizeof(filename),"%s2%s%s", ptcb->host_letter, ptcb->ptwin->host_letter,
3102 	    CONTENTS_FILE_EXTENSION);
3103     if (ptcb->extr_contents_file == (MFILE *) NULL) {
3104 	MFILE *f;
3105 
3106 	if ((f = Mfopen(filename,"w")) == NULL) {
3107 	    perror(filename);
3108 	    ptcb->extr_contents_file = (MFILE *) -1;
3109 	}
3110 
3111 	if (debug)
3112 	    fprintf(stderr,"TCP contents file is '%s'\n", filename);
3113 
3114 	ptcb->extr_contents_file = f;
3115 
3116 	if (ptcb->syn_count == 0) {
3117 	    /* we haven't seen the SYN.  This is bad because we can't tell */
3118 	    /* if there is data BEFORE this, which makes it tough to store */
3119 	    /* the file.  Let's be optimistic and hope we don't see */
3120 	    /* anything before this point.  Otherwise, we're stuck */
3121 	    ptcb->extr_lastseq = seq;
3122 	} else {
3123 	    /* beginning of the file is the data just past the SYN */
3124 	    ptcb->extr_lastseq = ptcb->syn+1;
3125 	}
3126 	/* in any case, anything before HERE is illegal (fails for very */
3127 	/* long files - FIXME */
3128 	ptcb->extr_initseq = ptcb->extr_lastseq;
3129     }
3130 
3131     /* it's illegal for the bytes to be BEFORE extr_initseq unless the file */
3132     /* is "really long" (seq space has wrapped around) - FIXME(ugly) */
3133     if ((SEQCMP(seq,ptcb->extr_initseq) < 0) &&
3134 	(ptcb->data_bytes < (0xffffffff/2))) {
3135 	/* if we haven't (didn't) seen the SYN, then can't do this!! */
3136 	if (debug>1) {
3137 	    fprintf(stderr,
3138 		    "ExtractContents: skipping data, preceeds first segment\n");
3139 	    fprintf(stderr,"\t and I didnt' see the SYN\n");
3140 	}
3141 	return;
3142     }
3143 
3144     /* see where we should start writing */
3145     /* a little complicated, because we want to support really long files */
3146     offset = SEQCMP(seq,ptcb->extr_lastseq);
3147 
3148 
3149     if (debug>10)
3150 	fprintf(stderr,
3151 		"TRYING to save %ld bytes from stream '%s2%s' at offset %ld\n",
3152 		saved_data_bytes,
3153 		ptcb->host_letter, ptcb->ptwin->host_letter,
3154 		offset);
3155 
3156     /* seek to the correct place in the file */
3157     if (Mfseek(ptcb->extr_contents_file, offset, SEEK_CUR) == -1) {
3158 	perror("fseek");
3159 	exit(-1);
3160     }
3161 
3162     /* see where we are */
3163     fptr = Mftell(ptcb->extr_contents_file);
3164 
3165     if (debug>1)
3166 	fprintf(stderr,
3167 		"Saving %ld bytes from '%s2%s' at offset %ld in file '%s'\n",
3168 		saved_data_bytes,
3169 		ptcb->host_letter, ptcb->ptwin->host_letter,
3170 		fptr, filename);
3171 
3172     /* store the bytes */
3173     if (Mfwrite(pdata,1,saved_data_bytes,ptcb->extr_contents_file)
3174 	!= saved_data_bytes) {
3175 	perror("fwrite");
3176 	exit(-1);
3177     }
3178 
3179     /* go back to where we started to not confuse the next write */
3180     ptcb->extr_lastseq = seq;
3181     if (Mfseek(ptcb->extr_contents_file, fptr, SEEK_SET) == -1) {
3182 	perror("fseek 2");
3183 	exit(-1);
3184     }
3185 }
3186 
3187 
3188 /* check for not-uncommon error of hardware-level duplicates
3189    (same IP ID and TCP sequence number) */
3190 static Bool
check_hw_dups(u_short id,seqnum seq,tcb * tcb)3191 check_hw_dups(
3192     u_short id,
3193     seqnum seq,
3194     tcb *tcb)
3195 {
3196     int i;
3197     struct str_hardware_dups *pshd;
3198 
3199     /* see if we've seen this one before */
3200     for (i=0; i < SEGS_TO_REMEMBER; ++i) {
3201 	pshd = &tcb->hardware_dups[i];
3202 
3203 	if ((pshd->hwdup_seq == seq) && (pshd->hwdup_id == id) &&
3204 	    (pshd->hwdup_seq != 0) && (pshd->hwdup_id != 0)) {
3205 	    /* count it */
3206 	    ++tcb->num_hardware_dups;
3207 	    if (warn_printhwdups) {
3208 		printf("%s->%s: saw hardware duplicate of TCP seq %lu, IP ID %u (packet %lu == %lu)\n",
3209 		       tcb->host_letter,tcb->ptwin->host_letter,
3210 		       seq, id, pnum,pshd->hwdup_packnum);
3211 	    }
3212 	    return(TRUE);
3213 	}
3214     }
3215 
3216     /* remember it */
3217     pshd = &tcb->hardware_dups[tcb->hardware_dups_ix];
3218     pshd->hwdup_seq = seq;
3219     pshd->hwdup_id = id;
3220     pshd->hwdup_packnum = pnum;
3221     tcb->hardware_dups_ix = (tcb->hardware_dups_ix+1) % SEGS_TO_REMEMBER;
3222 
3223     return(FALSE);
3224 }
3225 
3226 
3227 /* given a tcp_pair and a packet, tell me which tcb it is */
3228 struct tcb *
ptp2ptcb(tcp_pair * ptp,struct ip * pip,struct tcphdr * ptcp)3229 ptp2ptcb(
3230     tcp_pair *ptp,
3231     struct ip *pip,
3232     struct tcphdr *ptcp)
3233 {
3234     int dir = 0;
3235     tcp_pair tp_in;
3236 
3237     /* grab the address from this packet */
3238     CopyAddr(&tp_in.addr_pair, pip,
3239 	     ntohs(ptcp->th_sport), ntohs(ptcp->th_dport));
3240 
3241     /* check the direction */
3242     if (!SameConn(&tp_in.addr_pair,&ptp->addr_pair,&dir))
3243 	return(NULL);  /* not found, internal error */
3244 
3245     if (dir == A2B)
3246 	return(&ptp->a2b);
3247     else
3248 	return(&ptp->b2a);
3249 }
3250 
3251 
3252 /* represent the sequence numbers absolute or relative to 0 */
3253 static u_long
SeqRep(tcb * ptcb,u_long seq)3254 SeqRep(
3255     tcb *ptcb,
3256     u_long seq)
3257 {
3258     if (graph_seq_zero) {
3259 	return(seq - ptcb->min_seq);
3260     } else {
3261 	return(seq);
3262     }
3263 }
3264 
3265 
3266 /*------------------------------------------------------------------------
3267  *  cksum  -  Return 16-bit ones complement of 16-bit ones complement sum
3268  *------------------------------------------------------------------------
3269  */
3270 static u_short
cksum(void * pvoid,int nbytes)3271 cksum(
3272     void *pvoid,		/* any alignment is legal */
3273     int nbytes)
3274 {
3275     u_char *pchar = pvoid;
3276     u_long sum = 0;
3277 
3278     while (nbytes >= 2) {
3279 	/* can't assume pointer alignment :-( */
3280 	sum += (pchar[0]<<8);
3281 	sum += pchar[1];
3282 
3283 	pchar+=2;
3284 	nbytes -= 2;
3285     }
3286 
3287     /* special check for odd length */
3288     if (nbytes == 1) {
3289 	sum += (pchar[0]<<8);
3290 	/* lower byte is assumed to be 0 */
3291     }
3292 
3293     sum = (sum >> 16) + (sum & 0xffff);	/* add in carry   */
3294     sum += (sum >> 16);			/* maybe one more */
3295 
3296     return(sum);
3297 }
3298 
3299 /* compute IP checksum */
3300 static u_short
ip_cksum(struct ip * pip,void * plast)3301 ip_cksum(
3302     struct ip *pip,
3303     void *plast)
3304 {
3305     u_short sum;
3306 
3307     if (PIP_ISV6(pip))
3308 	return(0);		/* IPv6 has no header checksum */
3309     if (!PIP_ISV4(pip))
3310 	return(1);		/* I have no idea! */
3311 
3312 
3313     /* quick sanity check, if the packet is truncated, pretend it's valid */
3314     if ((char *)plast < (char *)((char *)pip+IP_HL(pip)*4-1)) {
3315 	return(0);
3316     }
3317 
3318     /* ... else IPv4 */
3319     sum = cksum(pip, IP_HL(pip)*4);
3320     return(sum);
3321 }
3322 
3323 
3324 /* is the IP checksum valid? */
3325 Bool
ip_cksum_valid(struct ip * pip,void * plast)3326 ip_cksum_valid(
3327     struct ip *pip,
3328     void *plast)
3329 {
3330     u_short sum;
3331 /*     PrintRawDataHex("IP header",pip,plast); */
3332 
3333     sum = ip_cksum(pip,plast);
3334 
3335     return((sum == 0) || (sum == 0xffff));
3336 }
3337 
3338 
3339 /* compute the TCP checksum */
3340 static u_short
tcp_cksum(struct ip * pip,struct tcphdr * ptcp,void * plast)3341 tcp_cksum(
3342     struct ip *pip,
3343     struct tcphdr *ptcp,
3344     void *plast)
3345 {
3346     u_long sum = 0;
3347     unsigned tcp_length = 0;
3348 
3349     /* verify version */
3350     if (!PIP_ISV4(pip) && !PIP_ISV6(pip)) {
3351 	fprintf(stderr,"Internal error, tcp_cksum: neither IPv4 nor IPv6\n");
3352 	exit(-1);
3353     }
3354 
3355 
3356     /* TCP checksum includes: */
3357     /* - IP source */
3358     /* - IP dest */
3359     /* - IP type */
3360     /* - TCP header length + TCP data length */
3361     /* - TCP header and data */
3362 
3363     if (PIP_ISV4(pip)) {
3364 	/* quick sanity check, if the packet is fragmented,
3365 	   pretend it's valid */
3366 	/* Thu Jul  6, 2000 - bugfix, bad check */
3367 	if (((ntohs(pip->ip_off) << 2) & 0xffff) != 0) {
3368 	    /* both the offset AND the MF bit must be 0 */
3369 	    /* (we shifted off the DF bit, which might be on) */
3370 	    return(0);
3371 	}
3372 
3373 	/* 2 4-byte numbers, next to each other */
3374 	sum += cksum(&pip->ip_src,4*2);
3375 
3376 	/* type */
3377 	sum += (u_short) pip->ip_p;
3378 
3379 	/* length (TCP header length + TCP data length) */
3380 	tcp_length = ntohs(pip->ip_len) - (4 * IP_HL(pip));
3381 	sum += (u_short) tcp_length;
3382     } else /* if (PIP_ISV6(pip))*/  {
3383 
3384         /* Support for IPv6 checksums has been added on Aug31, 2001
3385 	 * and has not been thoroughly tested. - Avinash
3386 	 */
3387 
3388         int total_length = 0;  /* Total length of the extension headers */
3389         struct ipv6 *pip6 = (struct ipv6 *)pip;
3390 
3391         /* quick sanity check, it the packet is truncated,
3392 	 * pertend it is valid.
3393 	 */
3394         if(gettcp(pip, &ptcp, &plast) != 0)
3395 	 return(0);
3396 
3397         /* Forming the pseudo-header */
3398         /* source address */
3399         sum += cksum(&pip6->ip6_saddr,16);
3400 
3401         /* Looking for the destination address.
3402 	 * May be in the IPv6 header or the last address in the
3403 	 * routing header (if present)
3404 	 */
3405 
3406         /* No extension headers, hence, routing header not present */
3407         if(pip6->ip6_nheader == IPPROTO_TCP) {
3408 	   sum += cksum(&pip6->ip6_daddr,16);
3409 	}
3410         /* Some extension headers present. Searching for routing header */
3411         else {
3412 	   /* find the first header */
3413 	   struct ipv6_ext *pipv6_ext = (struct ipv6_ext *)(pip6+1);
3414 
3415 	   /* Searching for the routing header */
3416 	   int ret = getroutingheader(pip, &pipv6_ext, &plast);
3417 
3418 	   if(!ret) {  /* Found the routing header */
3419 	      if(pipv6_ext->ip6ext_len >= 2) { /* Sanity check */
3420 		 char *daddr = (char *)((char *)pipv6_ext + 8 + ((pipv6_ext->ip6ext_len - 2) * 8));
3421 		 sum += cksum(&daddr,16);
3422 	      }
3423 	      else {  /* Not a valid routing header */
3424 		 return(-1);
3425 	      }
3426 	   }
3427 	   else {  /* Routing header not found */
3428 	      sum += cksum(&pip6->ip6_daddr,16);
3429 	   }
3430 	}
3431 
3432        /* Upper-Layer Packet Length */
3433        total_length = total_length_ext_headers(pip6);
3434        if(total_length >= 0)
3435 	 tcp_length = pip6->ip6_lngth - total_length;
3436        else /* Unknown extension header seen */
3437 	 return(-1);
3438        sum += (u_short) tcp_length;
3439 
3440        /* Next Header (Type) */
3441        sum += (u_short) IPPROTO_TCP;
3442     }
3443 
3444 
3445     /* quick sanity check, if the packet is truncated, pretend it's valid */
3446     if ((char *)plast < (char *)((char *)ptcp+tcp_length-1)) {
3447 	return(0);
3448     }
3449 
3450     /* checksum the TCP header and data */
3451     sum += cksum(ptcp,tcp_length);
3452 
3453     /* roll down into a 16-bit number */
3454     sum = (sum >> 16) + (sum & 0xffff);
3455     sum += (sum >> 16);
3456 
3457     return (u_short)(~sum & 0xffff);
3458 }
3459 
3460 
3461 
3462 /* compute the UDP checksum */
3463 static u_short
udp_cksum(struct ip * pip,struct udphdr * pudp,void * plast)3464 udp_cksum(
3465     struct ip *pip,
3466     struct udphdr *pudp,
3467     void *plast)
3468 {
3469     u_long sum = 0;
3470     unsigned udp_length;
3471 
3472     /* WARNING -- this routine has not been extensively tested */
3473 
3474     /* verify version */
3475     if (!PIP_ISV4(pip) && !PIP_ISV6(pip)) {
3476 	fprintf(stderr,"Internal error, udp_cksum: neither IPv4 nor IPv6\n");
3477 	exit(-1);
3478     }
3479 
3480 
3481     /* UDP checksum includes: */
3482     /* - IP source */
3483     /* - IP dest */
3484     /* - IP type */
3485     /* - UDP length field */
3486     /* - UDP header and data */
3487 
3488     if (PIP_ISV4(pip)) {
3489 	/* 2 4-byte numbers, next to each other */
3490 	sum += cksum(&pip->ip_src,4*2);
3491 
3492 	/* type */
3493 	sum += (u_short) pip->ip_p;
3494 
3495 	/* UDP length */
3496 	udp_length = ntohs(pudp->uh_ulen);
3497 	sum += htons(pudp->uh_ulen);
3498     } else /* if (PIP_ISV6(pip))*/  {
3499 
3500         /* Support for IPv6 checksums has been added on Aug31, 2001
3501 	 * and has not been thoroughly tested. - Avinash
3502 	 */
3503 
3504         struct ipv6 *pip6 = (struct ipv6 *)pip;
3505 
3506         /* quick sanity check, it the packet is truncated,
3507 	 * pertend it is valid.
3508 	 */
3509         if(getudp(pip, &pudp, &plast) != 0)
3510 	 return(0);
3511 
3512         /* Forming the pseudo-header */
3513         /* source address */
3514         sum += cksum(&pip6->ip6_saddr,16);
3515 
3516         /* Looking for the destination address.
3517 	 * May be in the IPv6 header or the last address in the
3518 	 * routing header (if present)
3519 	 */
3520 
3521         /* No extension headers, hence, routing header not present */
3522         if(pip6->ip6_nheader == IPPROTO_UDP) {
3523 	   sum += cksum(&pip6->ip6_daddr,16);
3524 	}
3525         /* Some extension headers present. Searching for routing header */
3526         else {
3527 	   /* find the first header */
3528 	   struct ipv6_ext *pipv6_ext = (struct ipv6_ext *)(pip6+1);
3529 
3530 	   /* Searching for the routing header */
3531 	   int ret = getroutingheader(pip, &pipv6_ext, &plast);
3532 
3533 	   if(!ret) {  /* Found the routing header */
3534 	      if(pipv6_ext->ip6ext_len >= 2) { /* Sanity check */
3535 		 char *daddr = (char *)((char *)pipv6_ext + 8 + ((pipv6_ext->ip6ext_len - 2) * 8));
3536 		 sum += cksum(&daddr,16);
3537 	      }
3538 	      else {  /* Not a valid routing header */
3539 		 return(-1);
3540 	      }
3541 	   }
3542 	   else {  /* Routing header not found */
3543 	      sum += cksum(&pip6->ip6_daddr,16);
3544 	   }
3545 	}
3546 
3547        /* Upper-Layer Packet Length */
3548 	udp_length = ntohs(pudp->uh_ulen);
3549 	sum += htons(pudp->uh_ulen);
3550 
3551        /* Next Header (Type) */
3552         sum += (u_short) IPPROTO_UDP;
3553     }
3554 
3555 
3556     /* quick sanity check, if the packet is truncated, pretend it's valid */
3557     if ((char *)plast < (char *)((char *)pudp+udp_length-1)) {
3558 	return(0);
3559     }
3560 
3561     /* checksum the UDP header and data */
3562     sum += cksum(pudp,udp_length);
3563 
3564     /* roll down into a 16-bit number */
3565     sum = (sum >> 16) + (sum & 0xffff);
3566     sum += (sum >> 16);
3567 
3568     return (u_short)(~sum & 0xffff);
3569 }
3570 
3571 
3572 /* is the TCP checksum valid? */
3573 Bool
tcp_cksum_valid(struct ip * pip,struct tcphdr * ptcp,void * plast)3574 tcp_cksum_valid(
3575     struct ip *pip,
3576     struct tcphdr *ptcp,
3577     void *plast)
3578 {
3579     return(tcp_cksum(pip,ptcp,plast) == 0);
3580 }
3581 
3582 
3583 /* is the UDP checksum valid? */
3584 Bool
udp_cksum_valid(struct ip * pip,struct udphdr * pudp,void * plast)3585 udp_cksum_valid(
3586     struct ip *pip,
3587     struct udphdr *pudp,
3588     void *plast)
3589 {
3590     if (ntohs(pudp->uh_sum) == 0) {
3591 	/* checksum not used */
3592 	return(1);		/* valid */
3593     }
3594 
3595     return(udp_cksum(pip,pudp,plast) == 0);
3596 }
3597 
3598 /* Did we miss any segment during packet capture? */
3599 static Bool
MissingData(tcp_pair * ptp)3600 MissingData(tcp_pair *ptp)
3601 {
3602   tcb *pab = &ptp->a2b;
3603   tcb *pba = &ptp->b2a;
3604 
3605   u_llong stream_length_pab=0, stream_length_pba=0;
3606   u_long pab_last, pba_last;
3607 
3608   /* If packets were truncated (due to shorter snaplen) we miss data */
3609   if ( (pab->trunc_bytes > 0) || (pba->trunc_bytes > 0) )
3610     return TRUE;
3611 
3612   /* Also, if we missed whole segments (pcap dozing off) we miss data.
3613    * The following code yanked off from output.c handles seq-space
3614    * wrap around - Mani
3615    *
3616    * Compare to theoretical length of the stream (not just what
3617    * we saw) using the SYN and FIN
3618    * Seq. Space wrap around calculations:
3619    * Calculate stream length using last_seq_num seen, first_seq_num
3620    * seen and wrap_count.
3621    * first_seq_num = syn
3622    * If reset_set, last_seq_num = latest_seq
3623    *          else last_seq_num = fin
3624    */
3625 
3626     pab_last = (pab->reset_count>0)?pab->latest_seq:pab->fin;
3627     pba_last = (pba->reset_count>0)?pba->latest_seq:pba->fin;
3628 
3629     /* calculating stream length for direction pab */
3630     if ((pab->syn_count > 0) && (pab->fin_count > 0)) {
3631 	if (pab->seq_wrap_count > 0) {
3632 	    if (pab_last > pab->syn) {
3633 		stream_length_pab = pab_last + (MAX_32 * pab->seq_wrap_count) - pab->syn - 1;
3634 	    }
3635 	    else {
3636 		stream_length_pab = pab_last + (MAX_32 * (pab->seq_wrap_count+1)) - pab->syn - 1;
3637 	    }
3638 	}
3639 	else {
3640 	    if (pab_last > pab->syn) {
3641 		stream_length_pab = pab_last - pab->syn - 1;
3642 	    }
3643 	    else {
3644 		stream_length_pab = MAX_32 + pab_last - pab->syn - 1;
3645 	    }
3646 	}
3647     }
3648 
3649     /* calculating stream length for direction pba */
3650     if ((pba->syn_count > 0) && (pba->fin_count > 0)) {
3651 	if (pba->seq_wrap_count > 0) {
3652 	    if (pba_last > pba->syn) {
3653 		stream_length_pba = pba_last + (MAX_32 * pba->seq_wrap_count) - pba->syn - 1;
3654 	    }
3655 	    else {
3656 		stream_length_pba = pba_last + (MAX_32 * (pba->seq_wrap_count+1)) - pba->syn - 1;
3657 	    }
3658 	}
3659 	else {
3660 	    if (pba_last > pba->syn) {
3661 		stream_length_pba = pba_last - pba->syn - 1;
3662 	    }
3663 	    else {
3664 		stream_length_pba = MAX_32 + pba_last - pba->syn - 1;
3665 	    }
3666 	}
3667     }
3668 
3669     /* Alright, now that we have the stream length in either direction,
3670      * if the stream length is not equal to the total unique bytes we
3671      * seen, we must have missed whole segments
3672      */
3673      if ( (stream_length_pab != pab->unique_bytes) ||
3674 	  (stream_length_pba != pba->unique_bytes) )
3675        return TRUE;
3676 
3677   return FALSE;
3678 }
3679