📄 tcp_output.c
字号:
/* Send it off. */ TCP_SKB_CB(skb)->seq = tcp_acceptable_seq(sk, tp); TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(skb)->seq; TCP_SKB_CB(skb)->when = tcp_time_stamp; if (tcp_transmit_skb(sk, skb)) NET_INC_STATS(LINUX_MIB_TCPABORTFAILED);}/* WARNING: This routine must only be called when we have already sent * a SYN packet that crossed the incoming SYN that caused this routine * to get called. If this assumption fails then the initial rcv_wnd * and rcv_wscale values will not be correct. */int tcp_send_synack(struct sock *sk){ struct sk_buff* skb; skb = skb_peek(&sk->sk_write_queue); if (skb == NULL || !(TCP_SKB_CB(skb)->flags&TCPCB_FLAG_SYN)) { printk(KERN_DEBUG "tcp_send_synack: wrong queue state\n"); return -EFAULT; } if (!(TCP_SKB_CB(skb)->flags&TCPCB_FLAG_ACK)) { if (skb_cloned(skb)) { struct sk_buff *nskb = skb_copy(skb, GFP_ATOMIC); if (nskb == NULL) return -ENOMEM; __skb_unlink(skb, &sk->sk_write_queue); __skb_queue_head(&sk->sk_write_queue, nskb); sk_stream_free_skb(sk, skb); sk_charge_skb(sk, nskb); skb = nskb; } TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_ACK; TCP_ECN_send_synack(tcp_sk(sk), skb); } TCP_SKB_CB(skb)->when = tcp_time_stamp; return tcp_transmit_skb(sk, skb_clone(skb, GFP_ATOMIC));}/* * Prepare a SYN-ACK. */struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst, struct open_request *req){ struct tcp_opt *tp = tcp_sk(sk); struct tcphdr *th; int tcp_header_size; struct sk_buff *skb; skb = sock_wmalloc(sk, MAX_TCP_HEADER + 15, 1, GFP_ATOMIC); if (skb == NULL) return NULL; /* Reserve space for headers. */ skb_reserve(skb, MAX_TCP_HEADER); skb->dst = dst_clone(dst); tcp_header_size = (sizeof(struct tcphdr) + TCPOLEN_MSS + (req->tstamp_ok ? TCPOLEN_TSTAMP_ALIGNED : 0) + (req->wscale_ok ? TCPOLEN_WSCALE_ALIGNED : 0) + /* SACK_PERM is in the place of NOP NOP of TS */ ((req->sack_ok && !req->tstamp_ok) ? TCPOLEN_SACKPERM_ALIGNED : 0)); skb->h.th = th = (struct tcphdr *) skb_push(skb, tcp_header_size); memset(th, 0, sizeof(struct tcphdr)); th->syn = 1; th->ack = 1; if (dst->dev->features&NETIF_F_TSO) req->ecn_ok = 0; TCP_ECN_make_synack(req, th); th->source = inet_sk(sk)->sport; th->dest = req->rmt_port; TCP_SKB_CB(skb)->seq = req->snt_isn; TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(skb)->seq + 1; TCP_SKB_CB(skb)->sacked = 0; skb_shinfo(skb)->tso_segs = 1; skb_shinfo(skb)->tso_size = 0; th->seq = htonl(TCP_SKB_CB(skb)->seq); th->ack_seq = htonl(req->rcv_isn + 1); if (req->rcv_wnd == 0) { /* ignored for retransmitted syns */ __u8 rcv_wscale; /* Set this up on the first call only */ req->window_clamp = tp->window_clamp ? : dst_metric(dst, RTAX_WINDOW); /* tcp_full_space because it is guaranteed to be the first packet */ tcp_select_initial_window(tcp_full_space(sk), dst_metric(dst, RTAX_ADVMSS) - (req->tstamp_ok ? TCPOLEN_TSTAMP_ALIGNED : 0), &req->rcv_wnd, &req->window_clamp, req->wscale_ok, &rcv_wscale); req->rcv_wscale = rcv_wscale; } /* RFC1323: The window in SYN & SYN/ACK segments is never scaled. */ th->window = htons(req->rcv_wnd); TCP_SKB_CB(skb)->when = tcp_time_stamp; tcp_syn_build_options((__u32 *)(th + 1), dst_metric(dst, RTAX_ADVMSS), req->tstamp_ok, req->sack_ok, req->wscale_ok, req->rcv_wscale, TCP_SKB_CB(skb)->when, req->ts_recent); skb->csum = 0; th->doff = (tcp_header_size >> 2); TCP_INC_STATS(TCP_MIB_OUTSEGS); return skb;}/* * Do all connect socket setups that can be done AF independent. */ static inline void tcp_connect_init(struct sock *sk){ struct dst_entry *dst = __sk_dst_get(sk); struct tcp_opt *tp = tcp_sk(sk); /* We'll fix this up when we get a response from the other end. * See tcp_input.c:tcp_rcv_state_process case TCP_SYN_SENT. */ tp->tcp_header_len = sizeof(struct tcphdr) + (sysctl_tcp_timestamps ? TCPOLEN_TSTAMP_ALIGNED : 0); /* If user gave his TCP_MAXSEG, record it to clamp */ if (tp->user_mss) tp->mss_clamp = tp->user_mss; tp->max_window = 0; tcp_sync_mss(sk, dst_pmtu(dst)); if (!tp->window_clamp) tp->window_clamp = dst_metric(dst, RTAX_WINDOW); tp->advmss = dst_metric(dst, RTAX_ADVMSS); tcp_initialize_rcv_mss(sk); tcp_ca_init(tp); tcp_select_initial_window(tcp_full_space(sk), tp->advmss - (tp->ts_recent_stamp ? tp->tcp_header_len - sizeof(struct tcphdr) : 0), &tp->rcv_wnd, &tp->window_clamp, sysctl_tcp_window_scaling, &tp->rcv_wscale); tp->rcv_ssthresh = tp->rcv_wnd; sk->sk_err = 0; sock_reset_flag(sk, SOCK_DONE); tp->snd_wnd = 0; tcp_init_wl(tp, tp->write_seq, 0); tp->snd_una = tp->write_seq; tp->snd_sml = tp->write_seq; tp->rcv_nxt = 0; tp->rcv_wup = 0; tp->copied_seq = 0; tp->rto = TCP_TIMEOUT_INIT; tp->retransmits = 0; tcp_clear_retrans(tp);}/* * Build a SYN and send it off. */ int tcp_connect(struct sock *sk){ struct tcp_opt *tp = tcp_sk(sk); struct sk_buff *buff; tcp_connect_init(sk); buff = alloc_skb(MAX_TCP_HEADER + 15, sk->sk_allocation); if (unlikely(buff == NULL)) return -ENOBUFS; /* Reserve space for headers. */ skb_reserve(buff, MAX_TCP_HEADER); TCP_SKB_CB(buff)->flags = TCPCB_FLAG_SYN; TCP_ECN_send_syn(sk, tp, buff); TCP_SKB_CB(buff)->sacked = 0; skb_shinfo(buff)->tso_segs = 1; skb_shinfo(buff)->tso_size = 0; buff->csum = 0; TCP_SKB_CB(buff)->seq = tp->write_seq++; TCP_SKB_CB(buff)->end_seq = tp->write_seq; tp->snd_nxt = tp->write_seq; tp->pushed_seq = tp->write_seq; tcp_ca_init(tp); /* Send it off. */ TCP_SKB_CB(buff)->when = tcp_time_stamp; tp->retrans_stamp = TCP_SKB_CB(buff)->when; __skb_queue_tail(&sk->sk_write_queue, buff); sk_charge_skb(sk, buff); tcp_inc_pcount(&tp->packets_out, buff); tcp_transmit_skb(sk, skb_clone(buff, GFP_KERNEL)); TCP_INC_STATS(TCP_MIB_ACTIVEOPENS); /* Timer for repeating the SYN until an answer. */ tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, tp->rto); return 0;}/* Send out a delayed ack, the caller does the policy checking * to see if we should even be here. See tcp_input.c:tcp_ack_snd_check() * for details. */void tcp_send_delayed_ack(struct sock *sk){ struct tcp_opt *tp = tcp_sk(sk); int ato = tp->ack.ato; unsigned long timeout; if (ato > TCP_DELACK_MIN) { int max_ato = HZ/2; if (tp->ack.pingpong || (tp->ack.pending&TCP_ACK_PUSHED)) max_ato = TCP_DELACK_MAX; /* Slow path, intersegment interval is "high". */ /* If some rtt estimate is known, use it to bound delayed ack. * Do not use tp->rto here, use results of rtt measurements * directly. */ if (tp->srtt) { int rtt = max(tp->srtt>>3, TCP_DELACK_MIN); if (rtt < max_ato) max_ato = rtt; } ato = min(ato, max_ato); } /* Stay within the limit we were given */ timeout = jiffies + ato; /* Use new timeout only if there wasn't a older one earlier. */ if (tp->ack.pending&TCP_ACK_TIMER) { /* If delack timer was blocked or is about to expire, * send ACK now. */ if (tp->ack.blocked || time_before_eq(tp->ack.timeout, jiffies+(ato>>2))) { tcp_send_ack(sk); return; } if (!time_before(timeout, tp->ack.timeout)) timeout = tp->ack.timeout; } tp->ack.pending |= TCP_ACK_SCHED|TCP_ACK_TIMER; tp->ack.timeout = timeout; sk_reset_timer(sk, &tp->delack_timer, timeout);}/* This routine sends an ack and also updates the window. */void tcp_send_ack(struct sock *sk){ /* If we have been reset, we may not send again. */ if (sk->sk_state != TCP_CLOSE) { struct tcp_opt *tp = tcp_sk(sk); struct sk_buff *buff; /* We are not putting this on the write queue, so * tcp_transmit_skb() will set the ownership to this * sock. */ buff = alloc_skb(MAX_TCP_HEADER, GFP_ATOMIC); if (buff == NULL) { tcp_schedule_ack(tp); tp->ack.ato = TCP_ATO_MIN; tcp_reset_xmit_timer(sk, TCP_TIME_DACK, TCP_DELACK_MAX); return; } /* Reserve space for headers and prepare control bits. */ skb_reserve(buff, MAX_TCP_HEADER); buff->csum = 0; TCP_SKB_CB(buff)->flags = TCPCB_FLAG_ACK; TCP_SKB_CB(buff)->sacked = 0; skb_shinfo(buff)->tso_segs = 1; skb_shinfo(buff)->tso_size = 0; /* Send it off, this clears delayed acks for us. */ TCP_SKB_CB(buff)->seq = TCP_SKB_CB(buff)->end_seq = tcp_acceptable_seq(sk, tp); TCP_SKB_CB(buff)->when = tcp_time_stamp; tcp_transmit_skb(sk, buff); }}/* This routine sends a packet with an out of date sequence * number. It assumes the other end will try to ack it. * * Question: what should we make while urgent mode? * 4.4BSD forces sending single byte of data. We cannot send * out of window data, because we have SND.NXT==SND.MAX... * * Current solution: to send TWO zero-length segments in urgent mode: * one is with SEG.SEQ=SND.UNA to deliver urgent pointer, another is * out-of-date with SND.UNA-1 to probe window. */static int tcp_xmit_probe_skb(struct sock *sk, int urgent){ struct tcp_opt *tp = tcp_sk(sk); struct sk_buff *skb; /* We don't queue it, tcp_transmit_skb() sets ownership. */ skb = alloc_skb(MAX_TCP_HEADER, GFP_ATOMIC); if (skb == NULL) return -1; /* Reserve space for headers and set control bits. */ skb_reserve(skb, MAX_TCP_HEADER); skb->csum = 0; TCP_SKB_CB(skb)->flags = TCPCB_FLAG_ACK; TCP_SKB_CB(skb)->sacked = urgent; skb_shinfo(skb)->tso_segs = 1; skb_shinfo(skb)->tso_size = 0; /* Use a previous sequence. This should cause the other * end to send an ack. Don't queue or clone SKB, just * send it. */ TCP_SKB_CB(skb)->seq = urgent ? tp->snd_una : tp->snd_una - 1; TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(skb)->seq; TCP_SKB_CB(skb)->when = tcp_time_stamp; return tcp_transmit_skb(sk, skb);}int tcp_write_wakeup(struct sock *sk){ if (sk->sk_state != TCP_CLOSE) { struct tcp_opt *tp = tcp_sk(sk); struct sk_buff *skb; if ((skb = sk->sk_send_head) != NULL && before(TCP_SKB_CB(skb)->seq, tp->snd_una+tp->snd_wnd)) { int err; unsigned int mss = tcp_current_mss(sk, 0); unsigned int seg_size = tp->snd_una+tp->snd_wnd-TCP_SKB_CB(skb)->seq; if (before(tp->pushed_seq, TCP_SKB_CB(skb)->end_seq)) tp->pushed_seq = TCP_SKB_CB(skb)->end_seq; /* We are probing the opening of a window * but the window size is != 0 * must have been a result SWS avoidance ( sender ) */ if (seg_size < TCP_SKB_CB(skb)->end_seq - TCP_SKB_CB(skb)->seq || skb->len > mss) { seg_size = min(seg_size, mss); TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH; if (tcp_fragment(sk, skb, seg_size)) return -1; /* SWS override triggered forced fragmentation. * Disable TSO, the connection is too sick. */ if (sk->sk_route_caps & NETIF_F_TSO) { sk->sk_no_largesend = 1; sk->sk_route_caps &= ~NETIF_F_TSO; tp->mss_cache = tp->mss_cache_std; } } else if (!tcp_skb_pcount(skb)) tcp_set_skb_tso_segs(skb, tp->mss_cache_std); TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH; TCP_SKB_CB(skb)->when = tcp_time_stamp; err = tcp_transmit_skb(sk, skb_clone(skb, GFP_ATOMIC)); if (!err) { update_send_head(sk, tp, skb); } return err; } else { if (tp->urg_mode && between(tp->snd_up, tp->snd_una+1, tp->snd_una+0xFFFF)) tcp_xmit_probe_skb(sk, TCPCB_URG); return tcp_xmit_probe_skb(sk, 0); } } return -1;}/* A window probe timeout has occurred. If window is not closed send * a partial packet else a zero probe. */void tcp_send_probe0(struct sock *sk){ struct tcp_opt *tp = tcp_sk(sk); int err; err = tcp_write_wakeup(sk); if (tcp_get_pcount(&tp->packets_out) || !sk->sk_send_head) { /* Cancel probe timer, if it is not required. */ tp->probes_out = 0; tp->backoff = 0; return; } if (err <= 0) { if (tp->backoff < sysctl_tcp_retries2) tp->backoff++; tp->probes_out++; tcp_reset_xmit_timer (sk, TCP_TIME_PROBE0, min(tp->rto << tp->backoff, TCP_RTO_MAX)); } else { /* If packet was not sent due to local congestion, * do not backoff and do not remember probes_out. * Let local senders to fight for local resources. * * Use accumulated backoff yet. */ if (!tp->probes_out) tp->probes_out=1; tcp_reset_xmit_timer (sk, TCP_TIME_PROBE0, min(tp->rto << tp->backoff, TCP_RESOURCE_PROBE_INTERVAL)); }}EXPORT_SYMBOL(tcp_acceptable_seq);EXPORT_SYMBOL(tcp_connect);EXPORT_SYMBOL(tcp_connect_init);EXPORT_SYMBOL(tcp_make_synack);EXPORT_SYMBOL(tcp_send_synack);EXPORT_SYMBOL(tcp_simple_retransmit);EXPORT_SYMBOL(tcp_sync_mss);EXPORT_SYMBOL(tcp_write_wakeup);EXPORT_SYMBOL(tcp_write_xmit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -