diff -Nrup linux-2.4.21-ori/Documentation/Configure.help linux-2.4.21-sfswap/Documentation/Configure.help --- linux-2.4.21-ori/Documentation/Configure.help 2003-08-17 15:37:06.000000000 +0200 +++ linux-2.4.21-sfswap/Documentation/Configure.help 2003-08-17 21:35:52.000000000 +0200 @@ -26649,6 +26649,18 @@ IPMI Watchdog Timer CONFIG_IPMI_WATCHDOG This enables the IPMI watchdog timer. +SYN/FIN Swap option +CONFIG_SFSWAP + This enables the SYN/FIN swap for a peer given in + /proc/sys/net/ipv4/tcp_sfswap_peer. In order to work, + you need the peer to have the same patch applied and + the sysctl configured for you to be its peer. + + If unsure, say N. + + See http://www.cartel-securite.fr/pbiondi/sfswap.html for + more infos. + # # A couple of things I keep forgetting: # capitalize: AppleTalk, Ethernet, DOS, DMA, FAT, FTP, Internet, diff -Nrup linux-2.4.21-ori/MAINTAINERS linux-2.4.21-sfswap/MAINTAINERS --- linux-2.4.21-ori/MAINTAINERS 2003-08-17 15:37:06.000000000 +0200 +++ linux-2.4.21-sfswap/MAINTAINERS 2003-08-17 23:05:27.000000000 +0200 @@ -1574,6 +1574,12 @@ P: Alan Cox M: alan@redhat.com S: Maintained for 2.2 only +SYN/FIN +P: Philippe Biondi +M: phil@secdev.org +W: http://www.secdev.org/sfswap.html +S: Maintained + UltraSPARC (sparc64): P: David S. Miller M: davem@redhat.com diff -Nrup linux-2.4.21-ori/include/linux/sysctl.h linux-2.4.21-sfswap/include/linux/sysctl.h --- linux-2.4.21-ori/include/linux/sysctl.h 2003-08-17 15:37:22.000000000 +0200 +++ linux-2.4.21-sfswap/include/linux/sysctl.h 2003-08-17 21:38:02.000000000 +0200 @@ -297,6 +297,7 @@ enum NET_TCP_FRTO=92, NET_TCP_LOW_LATENCY=93, NET_IPV4_IPFRAG_SECRET_INTERVAL=94, + NET_IPV4_TCP_SFSWAP_PEER=95, }; enum { diff -Nrup linux-2.4.21-ori/include/linux/tcp.h linux-2.4.21-sfswap/include/linux/tcp.h --- linux-2.4.21-ori/include/linux/tcp.h 2001-11-22 20:47:11.000000000 +0100 +++ linux-2.4.21-sfswap/include/linux/tcp.h 2003-08-17 22:52:36.000000000 +0200 @@ -114,6 +114,25 @@ enum { TCP_DATA_OFFSET = __constant_htonl(0xF0000000) }; +#ifdef CONFIG_SFSWAP +#define TCP_FLAG_SWSYN(host) ( ((host) != sysctl_tcp_sfswap_peer) ? \ + TCP_FLAG_SYN : TCP_FLAG_FIN ) +#define TCP_FLAG_SWFIN(host) ( ((host) != sysctl_tcp_sfswap_peer) ? \ + TCP_FLAG_FIN : TCP_FLAG_SYN ) +#define SWSYN(th, host) ( ((host) != sysctl_tcp_sfswap_peer) ? \ + ((th)->syn) : ((th)->fin) ) +#define SWFIN(th, host) ( ((host) != sysctl_tcp_sfswap_peer) ? \ + ((th)->fin) : ((th)->syn) ) +#define SET_SWSYN(th, host) do { if ((host) != sysctl_tcp_sfswap_peer) \ + (th)->syn = 1; else (th)->fin = 1; } while (0) +#else +#define TCP_FLAG_SWSYN(host) TCP_FLAG_SYN +#define TCP_FLAG_SWFIN(host) TCP_FLAG_FIN +#define SWSYN(th, host) ((th)->syn) +#define SWFIN(th, host) ((th)->fin) +#define SET_SWSYN(th, host) do {(th)->syn = 1; } while (0) +#endif /* CONFIG_SFSWAP */ + /* TCP socket options */ #define TCP_NODELAY 1 /* Turn off Nagle's algorithm. */ #define TCP_MAXSEG 2 /* Limit MSS */ diff -Nrup linux-2.4.21-ori/include/net/tcp.h linux-2.4.21-sfswap/include/net/tcp.h --- linux-2.4.21-ori/include/net/tcp.h 2003-08-17 15:37:22.000000000 +0200 +++ linux-2.4.21-sfswap/include/net/tcp.h 2003-08-17 22:53:01.000000000 +0200 @@ -463,6 +463,9 @@ extern int sysctl_tcp_adv_win_scale; extern int sysctl_tcp_tw_reuse; extern int sysctl_tcp_frto; extern int sysctl_tcp_low_latency; +#ifdef CONFIG_SFSWAP +extern int sysctl_tcp_sfswap_peer; +#endif extern atomic_t tcp_memory_allocated; extern atomic_t tcp_sockets_allocated; @@ -1015,6 +1018,16 @@ struct tcp_skb_cb { #define TCPCB_FLAG_ECE 0x40 #define TCPCB_FLAG_CWR 0x80 +#ifdef CONFIG_SFSWAP +#define TCPCB_FLAG_SWSYN(host) ( ((host) != sysctl_tcp_sfswap_peer) ? \ + TCPCB_FLAG_SYN : TCPCB_FLAG_FIN ) +#define TCPCB_FLAG_SWFIN(host) ( ((host) != sysctl_tcp_sfswap_peer) ? \ + TCPCB_FLAG_FIN : TCPCB_FLAG_SYN ) +#else +#define TCPCB_FLAG_SWSYN(host) TCPCB_FLAG_SYN +#define TCPCB_FLAG_SWFIN(host) TCPCB_FLAG_FIN +#endif + __u8 sacked; /* State flags for SACK/FACK. */ #define TCPCB_SACKED_ACKED 0x01 /* SKB ACK'd by a SACK block */ #define TCPCB_SACKED_RETRANS 0x02 /* SKB retransmitted */ diff -Nrup linux-2.4.21-ori/net/ipv4/Config.in linux-2.4.21-sfswap/net/ipv4/Config.in --- linux-2.4.21-ori/net/ipv4/Config.in 2001-12-21 18:42:05.000000000 +0100 +++ linux-2.4.21-sfswap/net/ipv4/Config.in 2003-08-17 18:24:23.000000000 +0200 @@ -44,3 +44,7 @@ bool ' IP: TCP syncookie support (disab if [ "$CONFIG_NETFILTER" != "n" ]; then source net/ipv4/netfilter/Config.in fi +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool ' IP: SYN/FIN swap for a given peer (EXPERIMENTAL)' CONFIG_SFSWAP +fi + diff -Nrup linux-2.4.21-ori/net/ipv4/sysctl_net_ipv4.c linux-2.4.21-sfswap/net/ipv4/sysctl_net_ipv4.c --- linux-2.4.21-ori/net/ipv4/sysctl_net_ipv4.c 2003-08-17 15:37:23.000000000 +0200 +++ linux-2.4.21-sfswap/net/ipv4/sysctl_net_ipv4.c 2003-08-17 21:38:27.000000000 +0200 @@ -89,6 +89,11 @@ static int ipv4_sysctl_forward_strategy( } ctl_table ipv4_table[] = { +#ifdef CONFIG_SFSWAP + {NET_IPV4_TCP_SFSWAP_PEER, "tcp_sfswap_peer", + &sysctl_tcp_sfswap_peer, sizeof(int), 0644, NULL, + &proc_dointvec}, +#endif {NET_IPV4_TCP_TIMESTAMPS, "tcp_timestamps", &sysctl_tcp_timestamps, sizeof(int), 0644, NULL, &proc_dointvec}, diff -Nrup linux-2.4.21-ori/net/ipv4/tcp.c linux-2.4.21-sfswap/net/ipv4/tcp.c --- linux-2.4.21-ori/net/ipv4/tcp.c 2003-08-17 15:37:23.000000000 +0200 +++ linux-2.4.21-sfswap/net/ipv4/tcp.c 2003-08-17 22:02:18.000000000 +0200 @@ -497,7 +497,7 @@ int tcp_ioctl(struct sock *sk, int cmd, /* Subtract 1, if FIN is in queue. */ if (answ && !skb_queue_empty(&sk->receive_queue)) - answ -= ((struct sk_buff*)sk->receive_queue.prev)->h.th->fin; + answ -= SWFIN(((struct sk_buff*)sk->receive_queue.prev)->h.th, sk->daddr); } else answ = tp->urg_seq - tp->copied_seq; release_sock(sk); @@ -1388,9 +1388,9 @@ struct sk_buff *tcp_recv_skb(struct sock skb_queue_walk(&sk->receive_queue, skb) { offset = seq - TCP_SKB_CB(skb)->seq; - if (skb->h.th->syn) + if (SWSYN(skb->h.th, sk->daddr)) offset--; - if (offset < skb->len || skb->h.th->fin) { + if (offset < skb->len || SWFIN(skb->h.th, sk->daddr)) { *off = offset; return skb; } @@ -1442,7 +1442,7 @@ int tcp_read_sock(struct sock *sk, read_ if (offset != skb->len) break; } - if (skb->h.th->fin) { + if (SWFIN(skb->h.th, sk->daddr)) { tcp_eat_skb(sk, skb); ++seq; break; @@ -1536,11 +1536,11 @@ int tcp_recvmsg(struct sock *sk, struct break; } offset = *seq - TCP_SKB_CB(skb)->seq; - if (skb->h.th->syn) + if (SWSYN(skb->h.th, sk->daddr)) offset--; if (offset < skb->len) goto found_ok_skb; - if (skb->h.th->fin) + if (SWFIN(skb->h.th, sk->daddr)) goto found_fin_ok; BUG_TRAP(flags&MSG_PEEK); skb = skb->next; @@ -1717,7 +1717,7 @@ skip_copy: if (used + offset < skb->len) continue; - if (skb->h.th->fin) + if (SWFIN(skb->h.th, sk->daddr)) goto found_fin_ok; if (!(flags & MSG_PEEK)) tcp_eat_skb(sk, skb); @@ -1921,7 +1921,7 @@ void tcp_close(struct sock *sk, long tim * reader process may not have drained the data yet! */ while((skb=__skb_dequeue(&sk->receive_queue))!=NULL) { - u32 len = TCP_SKB_CB(skb)->end_seq - TCP_SKB_CB(skb)->seq - skb->h.th->fin; + u32 len = TCP_SKB_CB(skb)->end_seq - TCP_SKB_CB(skb)->seq - SWFIN(skb->h.th, sk->daddr); data_was_unread += len; __kfree_skb(skb); } diff -Nrup linux-2.4.21-ori/net/ipv4/tcp_input.c linux-2.4.21-sfswap/net/ipv4/tcp_input.c --- linux-2.4.21-ori/net/ipv4/tcp_input.c 2003-08-17 15:37:23.000000000 +0200 +++ linux-2.4.21-sfswap/net/ipv4/tcp_input.c 2003-08-17 21:37:07.000000000 +0200 @@ -88,6 +88,9 @@ int sysctl_tcp_stdurg = 0; int sysctl_tcp_rfc1337 = 0; int sysctl_tcp_max_orphans = NR_FILE; int sysctl_tcp_frto = 0; +#ifdef CONFIG_SFSWAP +int sysctl_tcp_sfswap_peer = -1; +#endif #define FLAG_DATA 0x01 /* Incoming frame contained data. */ #define FLAG_WIN_UPDATE 0x02 /* Incoming ACK was a window update. */ @@ -1842,7 +1845,7 @@ static int tcp_clean_rtx_queue(struct so * connection startup slow start one packet too * quickly. This is severely frowned upon behavior. */ - if(!(scb->flags & TCPCB_FLAG_SYN)) { + if(!(scb->flags & TCPCB_FLAG_SWSYN(sk->daddr))) { acked |= FLAG_DATA_ACKED; } else { acked |= FLAG_SYN_ACKED; @@ -2141,7 +2144,7 @@ void tcp_parse_options(struct sk_buff *s return; /* don't parse partial options */ switch(opcode) { case TCPOPT_MSS: - if(opsize==TCPOLEN_MSS && th->syn && !estab) { + if(opsize==TCPOLEN_MSS && SWSYN(th,skb->nh.iph->saddr) && !estab) { u16 in_mss = ntohs(*(__u16 *)ptr); if (in_mss) { if (tp->user_mss && tp->user_mss < in_mss) @@ -2151,7 +2154,7 @@ void tcp_parse_options(struct sk_buff *s } break; case TCPOPT_WINDOW: - if(opsize==TCPOLEN_WINDOW && th->syn && !estab) + if(opsize==TCPOLEN_WINDOW && SWSYN(th, skb->nh.iph->saddr) && !estab) if (sysctl_tcp_window_scaling) { tp->wscale_ok = 1; tp->snd_wscale = *(__u8 *)ptr; @@ -2175,7 +2178,7 @@ void tcp_parse_options(struct sk_buff *s } break; case TCPOPT_SACK_PERM: - if(opsize==TCPOLEN_SACK_PERM && th->syn && !estab) { + if(opsize==TCPOLEN_SACK_PERM && SWSYN(th, skb->nh.iph->saddr) && !estab) { if (sysctl_tcp_sack) { tp->sack_ok = 1; tcp_sack_reset(tp); @@ -2630,7 +2633,7 @@ static void tcp_ofo_queue(struct sock *s __skb_unlink(skb, skb->list); __skb_queue_tail(&sk->receive_queue, skb); tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq; - if(skb->h.th->fin) + if(SWFIN(skb->h.th, sk->daddr)) tcp_fin(skb, sk, skb->h.th); } } @@ -2684,7 +2687,7 @@ static void tcp_data_queue(struct sock * if (!skb_copy_datagram_iovec(skb, 0, tp->ucopy.iov, chunk)) { tp->ucopy.len -= chunk; tp->copied_seq += chunk; - eaten = (chunk == skb->len && !th->fin); + eaten = (chunk == skb->len && !SWFIN(th, sk->daddr)); } local_bh_disable(); } @@ -2703,7 +2706,7 @@ queue_and_out: tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq; if(skb->len) tcp_event_data_recv(sk, tp, skb); - if(th->fin) + if(SWFIN(th, sk->daddr)) tcp_fin(skb, sk, th); if (skb_queue_len(&tp->out_of_order_queue)) { @@ -3252,7 +3255,7 @@ static inline void tcp_urg(struct sock * /* Do we wait for any urgent data? - normally not... */ if (tp->urg_data == TCP_URG_NOTYET) { - u32 ptr = tp->urg_seq - ntohl(th->seq) + (th->doff*4) - th->syn; + u32 ptr = tp->urg_seq - ntohl(th->seq) + (th->doff*4) - SWSYN(th, sk->daddr); /* Is the urgent pointer pointing into this packet? */ if (ptr < skb->len) { @@ -3543,7 +3546,7 @@ slow_path: tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->seq); - if (th->syn && !before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) { + if (SWSYN(th, sk->daddr) && !before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) { TCP_INC_STATS_BH(TcpInErrs); NET_INC_STATS_BH(TCPAbortOnSyn); tcp_reset(sk); @@ -3621,7 +3624,7 @@ static int tcp_rcv_synsent_state_process * See note below! * --ANK(990513) */ - if (!th->syn) + if (!SWSYN(th, sk->daddr)) goto discard_and_undo; /* rfc793: @@ -3731,7 +3734,7 @@ discard: if (tp->ts_recent_stamp && tp->saw_tstamp && tcp_paws_check(tp, 0)) goto discard_and_undo; - if (th->syn) { + if (SWSYN(th, sk->daddr)) { /* We see SYN without ACK. It is attempt of * simultaneous connect with crossed SYNs. * Particularly, it can be connect to self. @@ -3820,7 +3823,7 @@ int tcp_rcv_state_process(struct sock *s if(th->rst) goto discard; - if(th->syn) { + if(SWSYN(th,skb->nh.iph->saddr)) { if(tp->af_specific->conn_request(sk, skb) < 0) return 1; @@ -3887,7 +3890,7 @@ int tcp_rcv_state_process(struct sock *s * * Check for a SYN in window. */ - if (th->syn && !before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) { + if (SWSYN(th, sk->daddr) && !before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) { NET_INC_STATS_BH(TCPAbortOnSyn); tcp_reset(sk); return 1; @@ -3951,7 +3954,7 @@ int tcp_rcv_state_process(struct sock *s if (tp->linger2 < 0 || (TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq && - after(TCP_SKB_CB(skb)->end_seq - th->fin, tp->rcv_nxt))) { + after(TCP_SKB_CB(skb)->end_seq - SWFIN(th, sk->daddr), tp->rcv_nxt))) { tcp_done(sk); NET_INC_STATS_BH(TCPAbortOnData); return 1; @@ -3960,7 +3963,7 @@ int tcp_rcv_state_process(struct sock *s tmo = tcp_fin_time(tp); if (tmo > TCP_TIMEWAIT_LEN) { tcp_reset_keepalive_timer(sk, tmo - TCP_TIMEWAIT_LEN); - } else if (th->fin || sk->lock.users) { + } else if (SWFIN(th, sk->daddr) || sk->lock.users) { /* Bad case. We could lose such FIN otherwise. * It is not a big problem, but it looks confusing * and not so rare event. We still can lose it now, @@ -4012,7 +4015,7 @@ int tcp_rcv_state_process(struct sock *s */ if (sk->shutdown & RCV_SHUTDOWN) { if (TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq && - after(TCP_SKB_CB(skb)->end_seq - th->fin, tp->rcv_nxt)) { + after(TCP_SKB_CB(skb)->end_seq - SWFIN(th, sk->daddr), tp->rcv_nxt)) { NET_INC_STATS_BH(TCPAbortOnData); tcp_reset(sk); return 1; diff -Nrup linux-2.4.21-ori/net/ipv4/tcp_ipv4.c linux-2.4.21-sfswap/net/ipv4/tcp_ipv4.c --- linux-2.4.21-ori/net/ipv4/tcp_ipv4.c 2003-08-17 15:37:23.000000000 +0200 +++ linux-2.4.21-sfswap/net/ipv4/tcp_ipv4.c 2003-08-17 00:15:05.000000000 +0200 @@ -1620,7 +1620,7 @@ static struct sock *tcp_v4_hnd_req(struc } #ifdef CONFIG_SYN_COOKIES - if (!th->rst && !th->syn && th->ack) + if (!th->rst && !SWSYN(th, sk->daddr) && th->ack) sk = cookie_v4_check(sk, skb, &(IPCB(skb)->opt)); #endif return sk; diff -Nrup linux-2.4.21-ori/net/ipv4/tcp_minisocks.c linux-2.4.21-sfswap/net/ipv4/tcp_minisocks.c --- linux-2.4.21-ori/net/ipv4/tcp_minisocks.c 2003-08-17 15:37:23.000000000 +0200 +++ linux-2.4.21-sfswap/net/ipv4/tcp_minisocks.c 2003-08-17 14:02:09.000000000 +0200 @@ -154,7 +154,7 @@ tcp_timewait_state_process(struct tcp_tw if (th->rst) goto kill; - if (th->syn && !before(TCP_SKB_CB(skb)->seq, tw->rcv_nxt)) + if (SWSYN(th, skb->nh.iph->saddr) && !before(TCP_SKB_CB(skb)->seq, tw->rcv_nxt)) goto kill_with_rst; /* Dup ACK? */ @@ -167,7 +167,7 @@ tcp_timewait_state_process(struct tcp_tw /* New data or FIN. If new data arrive after half-duplex close, * reset. */ - if (!th->fin || TCP_SKB_CB(skb)->end_seq != tw->rcv_nxt+1) { + if (!SWFIN(th, skb->nh.iph->saddr) || TCP_SKB_CB(skb)->end_seq != tw->rcv_nxt+1) { kill_with_rst: tcp_tw_deschedule(tw); tcp_timewait_kill(tw); @@ -260,7 +260,7 @@ kill: but not fatal yet. */ - if (th->syn && !th->rst && !th->ack && !paws_reject && + if (SWSYN(th, skb->nh.iph->saddr) && !th->rst && !th->ack && !paws_reject && (after(TCP_SKB_CB(skb)->seq, tw->rcv_nxt) || (tp.saw_tstamp && (s32)(tw->ts_recent - tp.rcv_tsval) < 0))) { u32 isn = tw->snd_nxt+65535+2; @@ -802,7 +802,7 @@ struct sock *tcp_check_req(struct sock * { struct tcphdr *th = skb->h.th; struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); - u32 flg = tcp_flag_word(th) & (TCP_FLAG_RST|TCP_FLAG_SYN|TCP_FLAG_ACK); + u32 flg = tcp_flag_word(th) & (TCP_FLAG_RST|TCP_FLAG_SWSYN(skb->nh.iph->saddr)|TCP_FLAG_ACK); int paws_reject = 0; struct tcp_opt ttp; struct sock *child; @@ -824,7 +824,7 @@ struct sock *tcp_check_req(struct sock * /* Check for pure retransmitted SYN. */ if (TCP_SKB_CB(skb)->seq == req->rcv_isn && - flg == TCP_FLAG_SYN && + flg == TCP_FLAG_SWSYN(skb->nh.iph->saddr) && !paws_reject) { /* * RFC793 draws (Incorrectly! It was fixed in RFC1122) @@ -929,13 +929,13 @@ struct sock *tcp_check_req(struct sock * if (TCP_SKB_CB(skb)->seq == req->rcv_isn) { /* Truncate SYN, it is out of window starting at req->rcv_isn+1. */ - flg &= ~TCP_FLAG_SYN; + flg &= ~TCP_FLAG_SWSYN(skb->nh.iph->saddr); } /* RFC793: "second check the RST bit" and * "fourth, check the SYN bit" */ - if (flg & (TCP_FLAG_RST|TCP_FLAG_SYN)) + if (flg & (TCP_FLAG_RST|TCP_FLAG_SWSYN(skb->nh.iph->saddr))) goto embryonic_reset; /* ACK sequence verified above, just make sure ACK is diff -Nrup linux-2.4.21-ori/net/ipv4/tcp_output.c linux-2.4.21-sfswap/net/ipv4/tcp_output.c --- linux-2.4.21-ori/net/ipv4/tcp_output.c 2003-08-17 15:37:23.000000000 +0200 +++ linux-2.4.21-sfswap/net/ipv4/tcp_output.c 2003-08-17 17:00:08.000000000 +0200 @@ -201,7 +201,7 @@ int tcp_transmit_skb(struct sock *sk, st #define SYSCTL_FLAG_SACK 0x4 sysctl_flags = 0; - if (tcb->flags & TCPCB_FLAG_SYN) { + if (tcb->flags & TCPCB_FLAG_SWSYN(sk->daddr)) { tcp_header_size = sizeof(struct tcphdr) + TCPOLEN_MSS; if(sysctl_tcp_timestamps) { tcp_header_size += TCPOLEN_TSTAMP_ALIGNED; @@ -233,7 +233,7 @@ int tcp_transmit_skb(struct sock *sk, st th->seq = htonl(tcb->seq); th->ack_seq = htonl(tp->rcv_nxt); *(((__u16 *)th) + 6) = htons(((tcp_header_size >> 2) << 12) | tcb->flags); - if (tcb->flags & TCPCB_FLAG_SYN) { + if (tcb->flags & TCPCB_FLAG_SWSYN(sk->daddr)) { /* RFC1323: The window in SYN & SYN/ACK segments * is never scaled. */ @@ -249,8 +249,7 @@ int tcp_transmit_skb(struct sock *sk, st th->urg_ptr = htons(tp->snd_up-tcb->seq); th->urg = 1; } - - if (tcb->flags & TCPCB_FLAG_SYN) { + if (tcb->flags & TCPCB_FLAG_SWSYN(sk->daddr)) { tcp_syn_build_options((__u32 *)(th + 1), tcp_advertise_mss(sk), (sysctl_flags & SYSCTL_FLAG_TSTAMPS), @@ -442,7 +441,7 @@ static int tcp_fragment(struct sock *sk, /* PSH and FIN should only be set in the second packet. */ flags = TCP_SKB_CB(skb)->flags; - TCP_SKB_CB(skb)->flags = flags & ~(TCPCB_FLAG_FIN|TCPCB_FLAG_PSH); + TCP_SKB_CB(skb)->flags = flags & ~(TCPCB_FLAG_SWFIN(sk->daddr)|TCPCB_FLAG_PSH); TCP_SKB_CB(buff)->flags = flags; TCP_SKB_CB(buff)->sacked = TCP_SKB_CB(skb)->sacked&(TCPCB_LOST|TCPCB_EVER_RETRANS|TCPCB_AT_TAIL); if (TCP_SKB_CB(buff)->sacked&TCPCB_LOST) { @@ -839,7 +838,7 @@ int tcp_retransmit_skb(struct sock *sk, } /* Collapse two adjacent packets if worthwhile and we can. */ - if(!(TCP_SKB_CB(skb)->flags & TCPCB_FLAG_SYN) && + if(!(TCP_SKB_CB(skb)->flags & TCPCB_FLAG_SWSYN(sk->daddr)) && (skb->len < (cur_mss >> 1)) && (skb->next != tp->send_head) && (skb->next != (struct sk_buff *)&sk->write_queue) && @@ -855,7 +854,7 @@ int tcp_retransmit_skb(struct sock *sk, * since it is cheap to do so and saves bytes on the network. */ if(skb->len > 0 && - (TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN) && + (TCP_SKB_CB(skb)->flags & TCPCB_FLAG_SWFIN(sk->daddr)) && tp->snd_una == (TCP_SKB_CB(skb)->end_seq - 1)) { if (!pskb_trim(skb, 0)) { TCP_SKB_CB(skb)->seq = TCP_SKB_CB(skb)->end_seq - 1; @@ -1001,7 +1000,7 @@ void tcp_send_fin(struct sock *sk) mss_now = tcp_current_mss(sk); if(tp->send_head != NULL) { - TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_FIN; + TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_SWFIN(sk->daddr); TCP_SKB_CB(skb)->end_seq++; tp->write_seq++; } else { @@ -1016,7 +1015,7 @@ void tcp_send_fin(struct sock *sk) /* Reserve space for headers and prepare control bits. */ skb_reserve(skb, MAX_TCP_HEADER); skb->csum = 0; - TCP_SKB_CB(skb)->flags = (TCPCB_FLAG_ACK | TCPCB_FLAG_FIN); + TCP_SKB_CB(skb)->flags = (TCPCB_FLAG_ACK | TCPCB_FLAG_SWFIN(sk->daddr)); TCP_SKB_CB(skb)->sacked = 0; /* FIN eats a sequence byte, write_seq advanced by tcp_send_skb(). */ @@ -1068,7 +1067,7 @@ int tcp_send_synack(struct sock *sk) struct sk_buff* skb; skb = skb_peek(&sk->write_queue); - if (skb == NULL || !(TCP_SKB_CB(skb)->flags&TCPCB_FLAG_SYN)) { + if (skb == NULL || !(TCP_SKB_CB(skb)->flags&TCPCB_FLAG_SWSYN(sk->daddr))) { printk(KERN_DEBUG "tcp_send_synack: wrong queue state\n"); return -EFAULT; } @@ -1119,7 +1118,7 @@ struct sk_buff * tcp_make_synack(struct skb->h.th = th = (struct tcphdr *) skb_push(skb, tcp_header_size); memset(th, 0, sizeof(struct tcphdr)); - th->syn = 1; + SET_SWSYN(th, req->af.v4_req.rmt_addr); th->ack = 1; TCP_ECN_make_synack(req, th); th->source = sk->sport; @@ -1223,7 +1222,7 @@ int tcp_connect(struct sock *sk) /* Reserve space for headers. */ skb_reserve(buff, MAX_TCP_HEADER); - TCP_SKB_CB(buff)->flags = TCPCB_FLAG_SYN; + TCP_SKB_CB(buff)->flags = TCPCB_FLAG_SWSYN(sk->daddr); TCP_ECN_send_syn(tp, buff); TCP_SKB_CB(buff)->sacked = 0; buff->csum = 0;