Skip to content
Snippets Groups Projects
tcp.h 35.1 KiB
Newer Older
  • Learn to ignore specific revisions
  • Linus Torvalds's avatar
    Linus Torvalds committed
    			tp->rx_opt.dsack = 0;
    			tp->rx_opt.eff_sacks--;
    		}
    	}
    }
    
    /* Construct a tcp options header for a SYN or SYN_ACK packet.
     * If this is every changed make sure to change the definition of
     * MAX_SYN_SIZE to match the new maximum number of options that you
     * can generate.
     */
    static inline void tcp_syn_build_options(__u32 *ptr, int mss, int ts, int sack,
    					     int offer_wscale, int wscale, __u32 tstamp, __u32 ts_recent)
    {
    	/* We always get an MSS option.
    	 * The option bytes which will be seen in normal data
    	 * packets should timestamps be used, must be in the MSS
    	 * advertised.  But we subtract them from tp->mss_cache so
    	 * that calculations in tcp_sendmsg are simpler etc.
    	 * So account for this fact here if necessary.  If we
    	 * don't do this correctly, as a receiver we won't
    	 * recognize data packets as being full sized when we
    	 * should, and thus we won't abide by the delayed ACK
    	 * rules correctly.
    	 * SACKs don't matter, we never delay an ACK when we
    	 * have any of those going out.
    	 */
    	*ptr++ = htonl((TCPOPT_MSS << 24) | (TCPOLEN_MSS << 16) | mss);
    	if (ts) {
    		if(sack)
    			*ptr++ = __constant_htonl((TCPOPT_SACK_PERM << 24) | (TCPOLEN_SACK_PERM << 16) |
    						  (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP);
    		else
    			*ptr++ = __constant_htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
    						  (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP);
    		*ptr++ = htonl(tstamp);		/* TSVAL */
    		*ptr++ = htonl(ts_recent);	/* TSECR */
    	} else if(sack)
    		*ptr++ = __constant_htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
    					  (TCPOPT_SACK_PERM << 8) | TCPOLEN_SACK_PERM);
    	if (offer_wscale)
    		*ptr++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_WINDOW << 16) | (TCPOLEN_WINDOW << 8) | (wscale));
    }
    
    /* Determine a window scaling and initial window to offer. */
    extern void tcp_select_initial_window(int __space, __u32 mss,
    				      __u32 *rcv_wnd, __u32 *window_clamp,
    				      int wscale_ok, __u8 *rcv_wscale);
    
    static inline int tcp_win_from_space(int space)
    {
    	return sysctl_tcp_adv_win_scale<=0 ?
    		(space>>(-sysctl_tcp_adv_win_scale)) :
    		space - (space>>sysctl_tcp_adv_win_scale);
    }
    
    /* Note: caller must be prepared to deal with negative returns */ 
    static inline int tcp_space(const struct sock *sk)
    {
    	return tcp_win_from_space(sk->sk_rcvbuf -
    				  atomic_read(&sk->sk_rmem_alloc));
    } 
    
    static inline int tcp_full_space(const struct sock *sk)
    {
    	return tcp_win_from_space(sk->sk_rcvbuf); 
    }
    
    
    static __inline__ void tcp_openreq_init(struct request_sock *req,
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    					struct tcp_options_received *rx_opt,
    					struct sk_buff *skb)
    {
    
    	struct inet_request_sock *ireq = inet_rsk(req);
    
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	req->rcv_wnd = 0;		/* So that tcp_send_synack() knows! */
    
    	tcp_rsk(req)->rcv_isn = TCP_SKB_CB(skb)->seq;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	req->mss = rx_opt->mss_clamp;
    	req->ts_recent = rx_opt->saw_tstamp ? rx_opt->rcv_tsval : 0;
    
    	ireq->tstamp_ok = rx_opt->tstamp_ok;
    	ireq->sack_ok = rx_opt->sack_ok;
    	ireq->snd_wscale = rx_opt->snd_wscale;
    	ireq->wscale_ok = rx_opt->wscale_ok;
    	ireq->acked = 0;
    	ireq->ecn_ok = 0;
    	ireq->rmt_port = skb->h.th->source;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    
    extern void tcp_enter_memory_pressure(void);
    
    static inline int keepalive_intvl_when(const struct tcp_sock *tp)
    {
    	return tp->keepalive_intvl ? : sysctl_tcp_keepalive_intvl;
    }
    
    static inline int keepalive_time_when(const struct tcp_sock *tp)
    {
    	return tp->keepalive_time ? : sysctl_tcp_keepalive_time;
    }
    
    
    static inline int tcp_fin_time(const struct sock *sk)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    
    	int fin_timeout = tcp_sk(sk)->linger2 ? : sysctl_tcp_fin_timeout;
    	const int rto = inet_csk(sk)->icsk_rto;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    
    	if (fin_timeout < (rto << 2) - (rto >> 1))
    		fin_timeout = (rto << 2) - (rto >> 1);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    	return fin_timeout;
    }
    
    static inline int tcp_paws_check(const struct tcp_options_received *rx_opt, int rst)
    {
    	if ((s32)(rx_opt->rcv_tsval - rx_opt->ts_recent) >= 0)
    		return 0;
    	if (xtime.tv_sec >= rx_opt->ts_recent_stamp + TCP_PAWS_24DAYS)
    		return 0;
    
    	/* RST segments are not recommended to carry timestamp,
    	   and, if they do, it is recommended to ignore PAWS because
    	   "their cleanup function should take precedence over timestamps."
    	   Certainly, it is mistake. It is necessary to understand the reasons
    	   of this constraint to relax it: if peer reboots, clock may go
    	   out-of-sync and half-open connections will not be reset.
    	   Actually, the problem would be not existing if all
    	   the implementations followed draft about maintaining clock
    	   via reboots. Linux-2.2 DOES NOT!
    
    	   However, we can relax time bounds for RST segments to MSL.
    	 */
    	if (rst && xtime.tv_sec >= rx_opt->ts_recent_stamp + TCP_PAWS_MSL)
    		return 0;
    	return 1;
    }
    
    #define TCP_CHECK_TIMER(sk) do { } while (0)
    
    static inline int tcp_use_frto(const struct sock *sk)
    {
    	const struct tcp_sock *tp = tcp_sk(sk);
    	
    	/* F-RTO must be activated in sysctl and there must be some
    	 * unsent new data, and the advertised window should allow
    	 * sending it.
    	 */
    	return (sysctl_tcp_frto && sk->sk_send_head &&
    		!after(TCP_SKB_CB(sk->sk_send_head)->end_seq,
    		       tp->snd_una + tp->snd_wnd));
    }
    
    static inline void tcp_mib_init(void)
    {
    	/* See RFC 2012 */
    	TCP_ADD_STATS_USER(TCP_MIB_RTOALGORITHM, 1);
    	TCP_ADD_STATS_USER(TCP_MIB_RTOMIN, TCP_RTO_MIN*1000/HZ);
    	TCP_ADD_STATS_USER(TCP_MIB_RTOMAX, TCP_RTO_MAX*1000/HZ);
    	TCP_ADD_STATS_USER(TCP_MIB_MAXCONN, -1);
    }
    
    /* /proc */
    enum tcp_seq_states {
    	TCP_SEQ_STATE_LISTENING,
    	TCP_SEQ_STATE_OPENREQ,
    	TCP_SEQ_STATE_ESTABLISHED,
    	TCP_SEQ_STATE_TIME_WAIT,
    };
    
    struct tcp_seq_afinfo {
    	struct module		*owner;
    	char			*name;
    	sa_family_t		family;
    	int			(*seq_show) (struct seq_file *m, void *v);
    	struct file_operations	*seq_fops;
    };
    
    struct tcp_iter_state {
    	sa_family_t		family;
    	enum tcp_seq_states	state;
    	struct sock		*syn_wait_sk;
    	int			bucket, sbucket, num, uid;
    	struct seq_operations	seq_ops;
    };
    
    extern int tcp_proc_register(struct tcp_seq_afinfo *afinfo);
    extern void tcp_proc_unregister(struct tcp_seq_afinfo *afinfo);
    
    #endif	/* _TCP_H */