]> git.saurik.com Git - apple/network_cmds.git/blob - ecnprobe/ecn.c
82ebc0197897ee88b2b50490b319f94bf18bcb6e
[apple/network_cmds.git] / ecnprobe / ecn.c
1 /*
2 Copyright (c) 2000
3 International Computer Science Institute
4 All rights reserved.
5
6 This file may contain software code originally developed for the
7 Sting project. The Sting software carries the following copyright:
8
9 Copyright (c) 1998, 1999
10 Stefan Savage and the University of Washington.
11 All rights reserved.
12
13 Redistribution and use in source and binary forms, with or without
14 modification, are permitted provided that the following conditions
15 are met:
16 1. Redistributions of source code must retain the above copyright
17 notice, this list of conditions and the following disclaimer.
18 2. Redistributions in binary form must reproduce the above copyright
19 notice, this list of conditions and the following disclaimer in the
20 documentation and/or other materials provided with the distribution.
21 3. All advertising materials mentioning features or use of this software
22 must display the following acknowledgment:
23 This product includes software developed by ACIRI, the AT&T
24 Center for Internet Research at ICSI (the International Computer
25 Science Institute). This product may also include software developed
26 by Stefan Savage at the University of Washington.
27 4. The names of ACIRI, ICSI, Stefan Savage and University of Washington
28 may not be used to endorse or promote products derived from this software
29 without specific prior written permission.
30
31 THIS SOFTWARE IS PROVIDED BY ICSI AND CONTRIBUTORS ``AS IS'' AND
32 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
33 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
34 ARE DISCLAIMED. IN NO EVENT SHALL ICSI OR CONTRIBUTORS BE LIABLE
35 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
39 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
40 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
41 SUCH DAMAGE.
42 */
43 #include <sys/types.h>
44 #include <sys/param.h>
45 #include <sys/time.h>
46 #include <string.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <assert.h>
50 #include "base.h"
51 #include "inet.h"
52 #include "session.h"
53 #include "capture.h"
54 #include "support.h"
55 #include "history.h"
56 #include "ecn.h"
57
58 extern struct TcpSession session;
59 extern struct History history[];
60
61 #define ESTABLISH_SUCCESS 0
62 #define ESTABLISH_FAILURE_EARLY_RST 1
63 #define ESTABLISH_FAILURE_NO_REPLY 2
64 int EstablishTcpConnection(u_int8_t syn_flags, u_int8_t ip_tos)
65 {
66 struct IPPacket *synPacket = NULL, *ackPacket = NULL;
67 char *read_packet;
68 struct pcap_pkthdr pi;
69 int synAckReceived = 0;
70 int numRetransmits = 0;
71 double timeoutTime;
72 int tcpoptlen = 4; /* For negotiating MSS */
73 u_int8_t *opt = NULL;
74 struct IPPacket *p = NULL;
75 u_int16_t nmss;
76
77 /* allocate the syn packet -- Changed for new IPPacket structure */
78 synPacket = AllocateIPPacket(0, tcpoptlen, 0, "ECN (SYN)");
79 opt = (((u_int8_t *)synPacket->tcp) + sizeof(struct TcpHeader));
80 opt[0] = (u_int8_t)TCPOPT_MAXSEG;
81 opt[1] = (u_int8_t)TCPOLEN_MAXSEG;
82 *((u_int16_t *)((u_int8_t *)opt + 2)) = htons(session.mss);
83
84 SendSessionPacket(synPacket,
85 sizeof(struct IpHeader) + sizeof(struct TcpHeader) + tcpoptlen,
86 TCPFLAGS_SYN | syn_flags, 0, tcpoptlen, ip_tos);
87 timeoutTime = GetTime() + 1;
88
89 /*
90 * Wait for SYN/ACK and retransmit SYN if appropriate
91 * not great, but it gets the job done
92 */
93
94 while(!synAckReceived && numRetransmits < 3) {
95 while(GetTime() < timeoutTime) {
96 /* Have we captured any packets? */
97 if ((read_packet = (char *)CaptureGetPacket(&pi)) != NULL) {
98 p = (struct IPPacket *)FindHeaderBoundaries(read_packet);
99 /* Received a packet from us to them */
100 if (INSESSION(p, session.src, session.sport,
101 session.dst, session.dport)) {
102 /* Is it a SYN/ACK? */
103 if (p->tcp->tcp_flags & TCPFLAGS_SYN) {
104 if (session.debug >= SESSION_DEBUG_LOW) {
105 PrintTcpPacket(p);
106 }
107 StorePacket(p);
108 session.totSeenSent++ ;
109 } else {
110 processBadPacket(p);
111 }
112 continue;
113 }
114
115 /* Received a packet from them to us */
116 if (INSESSION(p, session.dst, session.dport, session.src,
117 session.sport)) {
118 /* Is it a SYN/ACK? */
119 if ((p->tcp->tcp_flags & TCPFLAGS_SYN) &&
120 (p->tcp->tcp_flags & TCPFLAGS_ACK)) {
121 timeoutTime = GetTime(); /* force exit */
122 synAckReceived++;
123 if (session.debug >= SESSION_DEBUG_LOW) {
124 PrintTcpPacket(p);
125 }
126 StorePacket(p);
127
128 /*
129 * Save ttl for,admittedly poor,indications of reverse
130 * route change
131 */
132 session.ttl = p->ip->ip_ttl;
133 session.snd_wnd = ntohl(p->tcp->tcp_win);
134 session.totRcvd ++;
135 break;
136 } else {
137 if ((p->tcp->tcp_flags)& (TCPFLAGS_RST)) {
138 printf ("ERROR: EARLY_RST\n");
139 return(ESTABLISH_FAILURE_EARLY_RST);
140 }
141 }
142 }
143 }
144 }
145
146 if (!synAckReceived) {
147 if (session.debug >= SESSION_DEBUG_LOW) {
148 printf("SYN timeout. Retransmitting\n");
149 }
150 SendSessionPacket(synPacket,
151 sizeof(struct IpHeader) + sizeof(struct TcpHeader) + tcpoptlen,
152 TCPFLAGS_SYN | syn_flags, 0, tcpoptlen, ip_tos);
153 timeoutTime = GetTime() + 1;
154 numRetransmits++;
155 }
156 }
157
158 if (numRetransmits >= 3) {
159 printf("ERROR: No connection after 3 retries...\nRETURN CODE: %d\n",
160 NO_CONNECTION);
161 return(ESTABLISH_FAILURE_NO_REPLY);
162 }
163 if (session.debug >= SESSION_DEBUG_LOW)
164 printf("Received SYN-ACK, try to send the third Ack\n");
165 /* Update session variables */
166 session.irs = ntohl(p->tcp->tcp_seq);
167 session.dataRcvd[0] = 1 ;
168 session.rcv_nxt = session.irs + 1; /* SYN/ACK takes up a byte of seq space */
169 session.snd_nxt = session.iss + 1; /* SYN takes up a byte of seq space */
170 session.snd_una = session.iss + 1;
171 session.maxseqseen = ntohl(p->tcp->tcp_seq);
172 session.initSession = 1;
173 if (session.debug >= SESSION_DEBUG_LOW) {
174 printf("src = %s:%d (%u)\n", InetAddress(session.src),
175 session.sport, session.iss);
176 printf("dst = %s:%d (%u)\n",InetAddress(session.dst),
177 session.dport, session.irs);
178 }
179
180 /* allocate the syn packet -- Changed for new IPPacket structure */
181 ackPacket = AllocateIPPacket(0, 0, 0, "Third ACK");
182 /* send an ACK */
183 SendSessionPacket(ackPacket,
184 sizeof(struct IpHeader) + sizeof(struct TcpHeader),
185 TCPFLAGS_ACK, 0, 0, 0);
186 FreeIPPacket(&synPacket);
187 FreeIPPacket(&ackPacket);
188 return(ESTABLISH_SUCCESS);
189 }
190
191 void ECNTest(u_int32_t sourceAddress, u_int16_t sourcePort,
192 u_int32_t targetAddress, u_int16_t targetPort, int mss)
193 {
194 int rawSocket, rc, flag = 1;
195
196 arc4random_stir();
197
198 session.src = sourceAddress;
199 session.sport = sourcePort;
200 session.dst = targetAddress;
201 session.dport = targetPort;
202 session.rcv_wnd = 5*mss;
203 /* random initial sequence number */
204 session.snd_nxt = arc4random();
205 session.iss = session.snd_nxt;
206 session.rcv_nxt = 0;
207 session.irs = 0;
208 session.mss = mss;
209 session.maxseqseen = 0;
210 session.epochTime = GetTime ();
211 session.maxpkts = 1000;
212 /* session.debug = SESSION_DEBUG_LOW; */
213 session.debug = 0;
214 if ((session.dataRcvd = (u_int8_t *)calloc(sizeof(u_int8_t),
215 mss * session.maxpkts)) == NULL) {
216 printf("no memmory to store data:\nRETURN CODE: %d",
217 ERR_MEM_ALLOC);
218 Quit(ERR_MEM_ALLOC);
219 }
220
221 if ((rawSocket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
222 perror("ERROR: couldn't open socket:");
223 Quit(ERR_SOCKET_OPEN);
224 }
225
226 if (setsockopt(rawSocket, IPPROTO_IP, IP_HDRINCL,
227 (char *)&flag, sizeof(flag)) < 0) {
228 perror("ERROR: couldn't set raw socket options:");
229 Quit(ERR_SOCKOPT);
230 }
231
232 session.socket = rawSocket;
233
234 /* Establish a TCP connections with ECN bits */
235 rc = EstablishTcpConnection(TCPFLAGS_ECN_ECHO | TCPFLAGS_CWR, 0);
236 switch (rc) {
237 case ESTABLISH_FAILURE_EARLY_RST:
238 {
239 /* Received a RST when ECN bits are used. Try again without ECN */
240 rc = EstablishTcpConnection(0, 0);
241 if (rc == ESTABLISH_FAILURE_EARLY_RST) {
242 printf("Received RST with or without ECN negotiation\n");
243 printf("The server might not be listening on this port\n");
244 Quit(EARLY_RST);
245 } else if (rc == ESTABLISH_SUCCESS) {
246 printf("Received RST with ECN.\n");
247 printf("Connection established successfully without ECN\n");
248 Quit(ECN_SYN_DROP);
249 } else if (rc == ESTABLISH_FAILURE_NO_REPLY) {
250 printf("Received RST with ECN\n");
251 printf("Exceed max SYN retransmits without ECN\n");
252 Quit(NO_CONNECTION);
253 }
254 break;
255 }
256 case ESTABLISH_FAILURE_NO_REPLY:
257 {
258 /* No reply after retring, try again without ECN */
259 rc = EstablishTcpConnection(0, 0);
260 if (rc == ESTABLISH_FAILURE_EARLY_RST) {
261 printf("Exceeded max SYN retransmits with ECN\n");
262 printf("Received RST without ECN\n");
263 Quit(NO_CONNECTION);
264 } else if (rc == ESTABLISH_FAILURE_NO_REPLY) {
265 printf("Exceeded max SYN retransmits with ECN\n");
266 printf("Exceeded max SYN retransmits without ECN\n");
267 Quit(NO_CONNECTION);
268 } else {
269 printf("Exceeded max SYN retransmits with ECN\n");
270 printf("Connection established successfully without ECN\n");
271 Quit(ECN_SYN_DROP);
272 }
273 break;
274 }
275 }
276
277 /* Test for propogation of CE correctly */
278 DataPkt(session.filename, 3, 0);
279
280 checkECN();
281 return;
282 }
283
284 void DataPkt (char *filename, u_int8_t iptos, u_int8_t tcp_flags)
285 {
286 struct IPPacket *p, *datapkt;
287 struct pcap_pkthdr pi;
288 char *read_packet;
289 int i ;
290 int sendflag = 1 ;
291 u_int16_t lastSeqSent = session.snd_nxt;
292 double startTime = 0;
293 char *dataptr ;
294 char data[MAXREQUESTLEN];
295 int datalen;
296 int ipsz;
297
298 datalen = PrepareRequest (data, filename);
299
300 datapkt = AllocateIPPacket(0, 0, datalen + 1, "ECN (datapkt)");
301
302 dataptr = (char *)datapkt->tcp + sizeof(struct TcpHeader);
303 memcpy((void *)dataptr,(void *)data, datalen);
304
305 ipsz = sizeof(struct IpHeader) + sizeof(struct TcpHeader) + datalen + 1;
306
307 /* send the data packet
308 * we try to "achieve" reliability by
309 * sending the packet upto 5 times, wating for
310 * 2 seconds between packets
311 * BAD busy-wait loop
312 */
313
314 i = 0 ;
315 while(1) {
316
317 if (sendflag == 1) {
318 SendSessionPacket(datapkt, ipsz,
319 TCPFLAGS_PSH | TCPFLAGS_ACK | tcp_flags, 0, 0, iptos);
320
321 startTime = GetTime();
322 sendflag = 0 ;
323 i++ ;
324 }
325
326 /* Check if we have received any packets */
327 if ((read_packet =(char *)CaptureGetPacket(&pi)) != NULL) {
328
329 p = (struct IPPacket *)FindHeaderBoundaries(read_packet);
330
331 /*
332 * packet that we sent?
333 */
334
335 if (INSESSION(p,session.src, session.sport,
336 session.dst,session.dport) &&
337 (p->tcp->tcp_flags == (TCPFLAGS_PSH | TCPFLAGS_ACK)) &&
338 SEQ_GT(ntohl(p->tcp->tcp_seq), lastSeqSent) &&
339 SEQ_LEQ(ntohl(p->tcp->tcp_ack), session.rcv_nxt)) {
340 lastSeqSent = ntohl(p->tcp->tcp_seq);
341 if (session.debug >= SESSION_DEBUG_LOW) {
342 printf("xmit %d\n", i);
343 PrintTcpPacket(p);
344 }
345 StorePacket(p);
346 session.snd_nxt += datalen + 1;
347 session.totSeenSent ++ ;
348 continue ;
349 }
350
351 /*
352 * from them?
353 */
354 if (INSESSION(p, session.dst, session.dport, session.src,
355 session.sport) && (p->tcp->tcp_flags & TCPFLAGS_ACK) &&
356 (ntohl(p->tcp->tcp_seq) == session.rcv_nxt) &&
357 SEQ_GT(ntohl(p->tcp->tcp_ack), session.snd_una)) {
358 session.snd_una = ntohl(p->tcp->tcp_ack);
359 session.snd_nxt = session.snd_una;
360 if (p->ip->ip_ttl != session.ttl) {
361 session.ttl = p->ip->ip_ttl;
362 }
363 if (session.debug >= SESSION_DEBUG_LOW) {
364 printf("rcvd %d\n", i);
365 PrintTcpPacket(p);
366 }
367 StorePacket(p);
368 session.totRcvd ++;
369 break ;
370 }
371 /*
372 * otherwise, this is a bad packet
373 * we must quit
374 */
375 //processBadPacket(p);
376 }
377 if ((GetTime() - startTime >= 1) && (sendflag == 0) && (i < 3)) {
378 sendflag = 1 ;
379 }
380 if (i >= 3) {
381 printf ("ERROR: sent request 3 times without response\n");
382 return;
383 }
384 }
385
386 FreeIPPacket(&datapkt);
387
388 /* process any response by sending Acks */
389 rcvData (ECNAckData);
390 }
391
392 void ECNAckData (struct IPPacket *p)
393 {
394
395 uint32 seq = history[session.hsz - 1].seqno;
396 uint16 datalen = history[session.hsz - 1].dlen;
397 int fin = history[session.hsz - 1].fin;
398 int rst = history[session.hsz - 1].rst;
399 int i;
400 struct IPPacket *ackpkt = NULL;
401 static int ECT_00 = 0;
402 static int ECT_01 = 0;
403 static int ECT_10 = 0;
404 static int ECT_11 = 0;
405 static int ECN_ECHO = 0;
406 static int send_cwr = 0;
407 static int send_ece = 0;
408 uint8 tcp_flags = 0;
409
410
411 /* Legend:
412 * ECN_ECHO: counts packets with TCP header ECN bit set
413 * ECT_XX: counts packets with ECT codepoint XX (IP)
414 */
415
416 if (datalen > session.mss) {
417 printf ("ERROR: mss=%d datalen=%d\nRETURN CODE: %d\n",
418 session.mss, datalen, MSS_ERR);
419 Quit(MSS_ERR);
420 }
421
422 if (datalen > 0) {
423 char *http_code = (char *)calloc(4, sizeof(char));
424 if (seq - session.irs == 1) {
425 /* Response to request packet --> check HTTP response code */
426 memcpy(http_code, ((char *)(p->tcp) + sizeof(struct TcpHeader) +
427 history[session.hsz - 1].optlen + 9), 3);
428 if (strncmp(http_code, HTTP_OK, 3) != 0) {
429 printf("HTTP ERROR - HTTP RESPONSE CODE: %s\nRETURN CODE: %d\n",
430 http_code, atoi(http_code));
431 Quit(atoi(http_code));
432 }
433 }
434
435 session.totDataPktsRcvd++;
436
437 if (session.verbose) {
438 printf ("r %f %d %d\n",
439 GetTime() - session.epochTime,
440 seq - session.irs,
441 seq - session.irs + datalen);
442 }
443
444 }
445
446 /* Check if packet has the ECN_ECHO flag set */
447 if (history[session.hsz - 1].ecn_echo) {
448 ECN_ECHO += 1;
449 }
450
451 if ((p->ip->ip_tos & 0x17) == 0) {
452 ECT_00 += 1;
453 }
454 if ((p->ip->ip_tos & 0x17) == 1) {
455 ECT_01 += 1;
456 }
457 if ((p->ip->ip_tos & 0x17) == 2) {
458 ECT_10 += 1;
459 }
460 if ((p->ip->ip_tos & 0x17) == 3) {
461 ECT_11 += 1;
462 }
463
464 if(session.maxseqseen < seq + datalen - 1) {
465 session.maxseqseen = seq + datalen - 1;
466 } else {
467 if (datalen > 0) {
468 if (reordered(p) != 1) {
469 session.num_unwanted_drops += 1;
470 }
471 }
472 }
473
474 /* from TCP/IP vol. 2, p 808 */
475 if (SEQ_LEQ(session.rcv_nxt, seq) &&
476 SEQ_LT(seq, (session.rcv_nxt + session.rcv_wnd)) &&
477 SEQ_LEQ(session.rcv_nxt, (seq + datalen)) &&
478 SEQ_LT((seq+datalen-1), (session.rcv_nxt + session.rcv_wnd))) {
479 int start, end;
480 start = seq - session.irs ;
481 end = start + datalen ;
482
483 for (i = start ; i < end ; i++) {
484 session.dataRcvd[i] = 1 ;
485 }
486
487 start = session.rcv_nxt - session.irs ;
488 end = session.mss * session.maxpkts ;
489
490 for (i = start ; i < end ; i++) {
491 if (session.dataRcvd[i] == 0) {
492 break ;
493 }
494 session.rcv_nxt++ ;
495 }
496 }
497
498 if (datalen > 0) {
499 if (session.verbose) {
500 printf ("a %f %d\n", GetTime() - session.epochTime,
501 session.rcv_nxt - session.irs);
502 }
503 ackpkt = AllocateIPPacket(0, 0, 0, "NewECN (ACK)");
504 if ((p->ip->ip_tos & 0x17) == 3) {
505 tcp_flags = TCPFLAGS_ACK | TCPFLAGS_ECN_ECHO;
506 } else {
507 tcp_flags = TCPFLAGS_ACK;
508 }
509
510 if (send_cwr == 2 && send_ece < 2) {
511 /* Send ECE as if a CE was received, we have to get CWR back */
512 send_ece = 1;
513 tcp_flags |= TCPFLAGS_ECN_ECHO;
514 }
515
516 SendSessionPacket (ackpkt,
517 sizeof(struct IpHeader) + sizeof(struct TcpHeader),
518 tcp_flags, 0, 0, 0);
519 }
520
521 if (send_cwr == 0 && (p->tcp->tcp_flags & TCPFLAGS_ECN_ECHO)) {
522 /* Send CWR atleast once if ECN ECHO is set */
523 int datalen;
524 struct IPPacket *datapkt;
525 char *dataptr;
526 char data[MAXREQUESTLEN];
527 int ipsz;
528
529 datalen = PrepareRequest(data, NULL);
530 datapkt = AllocateIPPacket(0, 0, datalen + 1, "ECN (datapkt)");
531 dataptr = (char *)datapkt->tcp + sizeof(struct TcpHeader);
532 memcpy((void *)dataptr, (void *)data, datalen);
533 ipsz = sizeof(struct IpHeader) + sizeof(struct TcpHeader) +
534 datalen + 1;
535
536 SendSessionPacket(datapkt, ipsz,
537 TCPFLAGS_PSH | TCPFLAGS_ACK | TCPFLAGS_CWR, 0, 0, 2);
538
539 send_cwr = 1;
540 FreeIPPacket(&datapkt);
541 }
542
543 if (send_cwr == 1 && !(p->tcp->tcp_flags & TCPFLAGS_ECN_ECHO)) {
544 /* ECE was reset in response to CWR, move to the next state of probing */
545 send_cwr = 2;
546 }
547
548 if (send_ece == 1 && (p->tcp->tcp_flags & TCPFLAGS_CWR)) {
549 /* Received CWR in response to ECE */
550 send_ece = 2;
551 }
552
553 if (SEQ_GT(ntohl(p->tcp->tcp_ack), session.snd_una))
554 session.snd_una = ntohl(p->tcp->tcp_ack);
555 if (SEQ_LT(session.snd_nxt, session.snd_una))
556 session.snd_nxt = session.snd_una;
557
558 if (fin || rst) {
559 /* Increment sequence number for FIN rcvd */
560 session.rcv_nxt++;
561 if (ECT_01 == 0 && ECT_10 == 0) {
562 printf("Never received ECT(0) or ECT(1) in ToS field: FAIL\n");
563 }
564 if (ECT_11 > 3) {
565 /* If we received more than 3 CE, flag it as an error */
566 printf("Received too many ECT_CE (%d): FAIL\n", ECT_11);
567 }
568 printf ("Totdata = %d ECN_ECHO: %d ECT00: %d ECT01: %d ECT10: %d ECT11: %d drops: %d\n",
569 session.rcv_nxt - session.irs, ECN_ECHO, ECT_00,
570 ECT_01, ECT_10, ECT_11, session.num_unwanted_drops);
571 if (fin) {
572 SendSessionPacket (ackpkt,
573 sizeof(struct IpHeader) + sizeof(struct TcpHeader),
574 tcp_flags, 0, 0, 0);
575 }
576 checkECN();
577 Quit(SUCCESS);
578 }
579 }
580
581 void checkECN ()
582 {
583 int i;
584 int sr = 0; /* sr=1: SYN/ACK rcvd */
585 int se = 0; /* se=0: no CWR/no ECHO; se=1: no CWR/ECHO; se=2: CWR/ECHO */
586 int ar = 0; /* ar=0: no ACK rcvd; ar=1: ACK rcvd */
587 int ae = 0; /* ae=0: ACK/no ECHO; ae=1: ACK/ECHO */
588 int we = 0; /* we=0: no ECHO; we=1 ECHO/CWR; we=2 ECHO/CWR/ECHO stop */
589 int ee = 0; /* ee=0 never sent ECE; ee=1 sent ECE; ee=2 ECE / CWR */
590
591 for (i = 0 ; i < session.hsz; i++) {
592 if ((history[i].type == RCVD) && (history[i].syn == 1) &&
593 (history[i].ack == 1)) {
594 sr = 1;
595 if (history[i].ecn_echo == 1) {
596 se = 1;
597 if (history[i].cwr == 1) {
598 se = 2;
599 }
600 }
601 }
602 }
603
604 for (i = 0 ; i < session.hsz; i++) {
605 if (history[i].type == RCVD && history[i].syn == 0 &&
606 history[i].ack == 1) {
607 ar = 1;
608 if (history[i].ecn_echo == 1) {
609 ae = 1;
610 }
611 }
612 }
613
614 for (i = 0; i < session.hsz; i++) {
615 if (history[i].type == SENT && history[i].dlen > 0 &&
616 history[i].cwr == 1) {
617 we = 1;
618 continue;
619 }
620 if (we == 1 && history[i].type == RCVD && history[i].ecn_echo == 0) {
621 we = 2;
622 break;
623 }
624 if (we == 2 && history[i].type == RCVD && history[i].ecn_echo == 1) {
625 we = 1;
626 break;
627 }
628 }
629
630 for (i = 0; i < session.hsz; i++) {
631 if (history[i].type == SENT && history[i].ecn_echo == 1) {
632 ee = 1;
633 continue;
634 }
635 if (ee == 1 && history[i].type == RCVD && history[i].dlen > 0 &&
636 history[i].cwr == 1) {
637 /* Received cwr in response to ECE */
638 ee = 2;
639 break;
640 }
641 }
642
643 printf ("sr=%d se=%d ar=%d ae=%d we=%d\n", sr, se, ar, ae, we);
644 switch (sr) {
645 case 0:
646 printf("No SYN/ACK received from server\n");
647 break;
648 case 1:
649 printf("SYN/ACK received: PASS \n");
650 break;
651 default:
652 printf("Unknown value for sr: %d\n", sr);
653 break;
654 }
655 switch (se) {
656 case 0:
657 printf("No CWR or ECE on SYN/ACK, server does not support ECN\n");
658 break;
659 case 1:
660 printf("ECE flag set on SYN/ACK, server supports ECN: PASS\n");
661 break;
662 case 2:
663 printf("Both CWR and ECE set on SYN/ACK, incompatible SYN/ACK\n");
664 break;
665 default:
666 printf("Unknown value for se: %d\n", se);
667 break;
668 }
669
670 switch (ar) {
671 case 0:
672 printf("No ACK received\n");
673 break;
674 case 1:
675 printf("ACK received: PASS\n");
676 break;
677 default:
678 printf("Unknown value for ar: %d\n", ar);
679 break;
680 }
681
682 switch (ae) {
683 case 0:
684 printf("Received ACKS but never ECE\n");
685 break;
686 case 1:
687 printf("Received ACKs with ECE, in response to simulated CE bit: PASS\n");
688 break;
689 default:
690 printf("Unknown value for ae: %d\n", ae);
691 break;
692 }
693
694 switch (we) {
695 case 0:
696 printf("Never received ECE\n");
697 break;
698 case 1:
699 printf("Received ECE and sent CWR\n");
700 break;
701 case 2:
702 printf("Received ECE, sent CWR and stopped receiving ECE afterwards: PASS\n");
703 break;
704 default:
705 printf("Unknown value for we: %d\n", we);
706 break;
707 }
708
709 switch (ee) {
710 case 0:
711 printf("Never sent ECE\n");
712 break;
713 case 1:
714 printf("Sent ECE to simulate receiving CE \n");
715 break;
716 case 2:
717 printf("Sent ECE and received CWR in response: PASS\n");
718 break;
719 default:
720 printf("Unknown value for ee: %d\n", ee);
721 break;
722 }
723 return;
724 }