📄 mytcp_input.c
字号:
static inline void mytcp_data_snd_check(struct sock *sk, struct tcp_sock *tp);static void mytcp_urg(struct sock *sk, struct sk_buff *skb, struct tcphdr *th){}static inline int mytcp_in_quickack_mode(const struct sock *sk){ const struct inet_connection_sock *icsk = inet_csk(sk); return icsk->icsk_ack.quick && !icsk->icsk_ack.pingpong;}static void __mytcp_ack_snd_check(struct sock *sk, int ofo_possible){ struct tcp_sock *tp = tcp_sk(sk); if (((tp->rcv_nxt - tp->rcv_wup) > inet_csk(sk)->icsk_ack.rcv_mss && __mytcp_select_window(sk) >= tp->rcv_wnd) || mytcp_in_quickack_mode(sk) || (ofo_possible && skb_peek(&tp->out_of_order_queue))) { mytcp_send_ack(sk); } else { mytcp_send_delayed_ack(sk); }}static inline void mytcp_ack_snd_check(struct sock *sk){ if( !inet_csk_ack_scheduled(sk) ){ return; } __mytcp_ack_snd_check(sk, 1);}static int mytcp_copy_to_iovec(struct sock *sk, struct sk_buff *skb, int hlen){ struct tcp_sock *tp = tcp_sk(sk); int chunk = skb->len - hlen; int err; local_bh_enable(); if (skb->ip_summed==CHECKSUM_UNNECESSARY) err = skb_copy_datagram_iovec(skb, hlen, tp->ucopy.iov, chunk); else err = skb_copy_and_csum_datagram_iovec(skb, hlen, tp->ucopy.iov); if (!err) { tp->ucopy.len -= chunk; tp->copied_seq += chunk; mytcp_rcv_space_adjust(sk); } local_bh_disable(); return err;}int mytcp_rcv_established(struct sock *sk, struct sk_buff *skb, struct tcphdr *th, unsigned len){ struct tcp_sock *tp = tcp_sk(sk); tp->rx_opt.saw_tstamp = 0; if( (tcp_flag_word(th) & TCP_HP_BITS) == tp->pred_flags && TCP_SKB_CB(skb)->seq == tp->rcv_nxt) { int tcp_header_len = tp->tcp_header_len; if( tcp_header_len == sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED ){ __u32 *ptr = (__u32 *)(th + 1); if (*ptr != ntohl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP)) goto slow_path; tp->rx_opt.saw_tstamp = 1; ++ptr; tp->rx_opt.rcv_tsval = ntohl(*ptr); ++ptr; tp->rx_opt.rcv_tsecr = ntohl(*ptr); if ((s32)(tp->rx_opt.rcv_tsval - tp->rx_opt.ts_recent) < 0) goto slow_path; } if( len <= tcp_header_len ){ if( len == tcp_header_len ){ if (tcp_header_len == (sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED) && tp->rcv_nxt == tp->rcv_wup) mytcp_store_ts_recent(tp); mytcp_rcv_rtt_measure_ts(sk, skb); mytcp_ack(sk, skb, 0); __kfree_skb(skb); mytcp_data_snd_check(sk, tp); return 0; }else{ MYTCP_INC_STATS_BH(TCP_MIB_INERRS); goto discard; } }else{ int eaten = 0; printk(KERN_INFO "%s:%d: %p==%p\n", __FUNCTION__, __LINE__, tp->ucopy.task, current); if (tp->ucopy.task == current && tp->copied_seq == tp->rcv_nxt && len - tcp_header_len <= tp->ucopy.len && sock_owned_by_user(sk)){ __set_current_state(TASK_RUNNING); if (!mytcp_copy_to_iovec(sk, skb, tcp_header_len)) { if (tcp_header_len == (sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED) && tp->rcv_nxt == tp->rcv_wup) mytcp_store_ts_recent(tp); mytcp_rcv_rtt_measure_ts(sk, skb); __skb_pull(skb, tcp_header_len); tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq; NET_INC_STATS_BH(LINUX_MIB_TCPHPHITSTOUSER); eaten = 1; } } if (!eaten) { if( mytcp_checksum_complete_user(sk, skb) ) goto csum_error; if (tcp_header_len == (sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED) && tp->rcv_nxt == tp->rcv_wup) mytcp_store_ts_recent(tp); mytcp_rcv_rtt_measure_ts(sk, skb); if ((int)skb->truesize > sk->sk_forward_alloc) goto step5; NET_INC_STATS_BH(LINUX_MIB_TCPHPHITS); __skb_pull(skb,tcp_header_len); __skb_queue_tail(&sk->sk_receive_queue, skb); sk_stream_set_owner_r(skb, sk); tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq; } mytcp_event_data_recv(sk, tp, skb); if (TCP_SKB_CB(skb)->ack_seq != tp->snd_una) { mytcp_ack(sk, skb, FLAG_DATA); mytcp_data_snd_check(sk, tp); if (!inet_csk_ack_scheduled(sk)) goto no_ack; } __mytcp_ack_snd_check(sk, 0);no_ack: if (eaten) __kfree_skb(skb); else sk->sk_data_ready(sk, 0); printk(KERN_INFO "%s:%d: the rcv wnd: %d\n", __FUNCTION__, __LINE__, tp->rcv_wnd ); return 0; } }slow_path: if (len < (th->doff<<2) || mytcp_checksum_complete_user(sk, skb)) goto csum_error; if( mytcp_fast_parse_options(skb, th, tp) && tp->rx_opt.saw_tstamp && mytcp_paws_discard(sk, skb) ){ if (!th->rst) { MYNET_INC_STATS_BH(LINUX_MIB_PAWSESTABREJECTED); mytcp_send_dupack(sk, skb); goto discard; } } if (!mytcp_sequence(tp, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq)) { if (!th->rst) mytcp_send_dupack(sk, skb); goto discard; } if(th->rst) { mytcp_reset(sk); goto discard; } mytcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->seq); if( th->syn && !before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt) ){ MYTCP_INC_STATS_BH(TCP_MIB_INERRS); MYNET_INC_STATS_BH(LINUX_MIB_TCPABORTONSYN); mytcp_reset(sk); return 1; }step5: if(th->ack) mytcp_ack(sk, skb, FLAG_SLOWPATH); mytcp_rcv_rtt_measure_ts(sk, skb); mytcp_urg(sk, skb, th); mytcp_data_queue(sk, skb); mytcp_data_snd_check(sk, tp); mytcp_ack_snd_check(sk); return 0;csum_error: TCP_INC_STATS_BH(TCP_MIB_INERRS);discard: __kfree_skb(skb); return 0;}void mytcp_parse_options(struct sk_buff *skb, struct tcp_options_received *opt_rx, int estab){ unsigned char *ptr; struct tcphdr *th = skb->h.th; int length=(th->doff*4)-sizeof(struct tcphdr); ptr = (unsigned char *)(th + 1); opt_rx->saw_tstamp = 0; while(length>0) { int opcode=*ptr++; int opsize; switch (opcode) { case TCPOPT_EOL: return; case TCPOPT_NOP: length--; continue; default: opsize=*ptr++; if (opsize < 2) return; if (opsize > length) return; switch(opcode) { case TCPOPT_MSS: if(opsize==TCPOLEN_MSS && th->syn && !estab) { u16 in_mss = ntohs(get_unaligned( (__u16 *)ptr) ); if( in_mss ){ if (opt_rx->user_mss && opt_rx->user_mss < in_mss) in_mss = opt_rx->user_mss; opt_rx->mss_clamp = in_mss; } } break; case TCPOPT_WINDOW: if(opsize==TCPOLEN_WINDOW && th->syn && !estab) if (mysysctl_tcp_window_scaling) { __u8 snd_wscale = *(__u8 *) ptr; opt_rx->wscale_ok = 1; if (snd_wscale > 14) { if(net_ratelimit()) printk(KERN_INFO "tcp_parse_options: Illegal window " "scaling value %d >14 received.\n", snd_wscale); snd_wscale = 14; } opt_rx->snd_wscale = snd_wscale; } break; case TCPOPT_TIMESTAMP: if(opsize==TCPOLEN_TIMESTAMP) { if ((estab && opt_rx->tstamp_ok) || (!estab && mysysctl_tcp_timestamps)) { opt_rx->saw_tstamp = 1; opt_rx->rcv_tsval = ntohl(get_unaligned((__u32 *)ptr)); opt_rx->rcv_tsecr = ntohl(get_unaligned((__u32 *)(ptr+4))); } } break; case TCPOPT_SACK_PERM: if(opsize==TCPOLEN_SACK_PERM && th->syn && !estab) { if( mysysctl_tcp_sack ){ opt_rx->sack_ok = 1; tcp_sack_reset(opt_rx); } } break; case TCPOPT_SACK: if((opsize >= (TCPOLEN_SACK_BASE + TCPOLEN_SACK_PERBLOCK)) && !((opsize - TCPOLEN_SACK_BASE) % TCPOLEN_SACK_PERBLOCK) && opt_rx->sack_ok){ TCP_SKB_CB(skb)->sacked = (ptr - 2) - (unsigned char *)th; } } ptr+=opsize-2; length-=opsize; } }}static int mytcp_ack_update_window(struct sock *sk, struct tcp_sock *tp, struct sk_buff *skb, u32 ack, u32 ack_seq){ int flag = 0; u32 nwin = ntohs(skb->h.th->window); if (likely(!skb->h.th->syn)) nwin <<= tp->rx_opt.snd_wscale; //printk(KERN_INFO "%s:%s:%d: the window len: %d\n", __FILE__, __FUNCTION__, __LINE__, nwin ); if( mytcp_may_update_window(tp, ack, ack_seq, nwin) ){ flag |= FLAG_WIN_UPDATE; tcp_update_wl(tp, ack, ack_seq); if (tp->snd_wnd != nwin) { tp->snd_wnd = nwin; tp->pred_flags = 0; tcp_fast_path_check(sk, tp); if (nwin > tp->max_window) { tp->max_window = nwin; mytcp_sync_mss(sk, inet_csk(sk)->icsk_pmtu_cookie); } } } tp->snd_una = ack; return flag;}static void mytcp_update_reordering(struct sock *sk, const int metric, const int ts){ struct tcp_sock *tp = tcp_sk(sk); if( metric > tp->reordering ){ tp->reordering = min(TCP_MAX_REORDERING, metric); if (ts) MYNET_INC_STATS_BH(LINUX_MIB_TCPTSREORDER); else if (IsReno(tp)) MYNET_INC_STATS_BH(LINUX_MIB_TCPRENOREORDER); else if (IsFack(tp)) MYNET_INC_STATS_BH(LINUX_MIB_TCPFACKREORDER); else MYNET_INC_STATS_BH(LINUX_MIB_TCPSACKREORDER);#if FASTRETRANS_DEBUG > 1 printk(KERN_DEBUG "Disorder%d %d %u f%u s%u rr%d\n", tp->rx_opt.sack_ok, inet_csk(sk)->icsk_ca_state, tp->reordering, tp->fackets_out, tp->sacked_out, tp->undo_marker ? tp->undo_retrans : 0);#endif tp->rx_opt.sack_ok &= ~2; }}static int mytcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_una){ const struct inet_connection_sock *icsk = inet_csk(sk); struct tcp_sock *tp = tcp_sk(sk); unsigned char *ptr = ack_skb->h.raw + TCP_SKB_CB(ack_skb)->sacked; struct tcp_sack_block *sp = (struct tcp_sack_block *)(ptr+2); int num_sacks = (ptr[1] - TCPOLEN_SACK_BASE)>>3; int reord = tp->packets_out; int prior_fackets; u32 lost_retrans = 0; int flag = 0; int dup_sack = 0; int i; printk(KERN_INFO "%s:%d: the sacked: %d\n", __FUNCTION__, __LINE__, TCP_SKB_CB(ack_skb)->sacked ); if (!tp->sacked_out) tp->fackets_out = 0; prior_fackets = tp->fackets_out; flag = 1; for (i = 0; i< num_sacks; i++) { __u32 start_seq = ntohl(sp[i].start_seq); __u32 end_seq = ntohl(sp[i].end_seq); if (i == 0){ if (tp->recv_sack_cache[i].start_seq != start_seq) flag = 0; } else { if ((tp->recv_sack_cache[i].start_seq != start_seq) || (tp->recv_sack_cache[i].end_seq != end_seq)) flag = 0; } tp->recv_sack_cache[i].start_seq = start_seq; tp->recv_sack_cache[i].end_seq = end_seq; if (i == 0) { u32 ack = TCP_SKB_CB(ack_skb)->ack_seq; if( before(start_seq, ack) ){ dup_sack = 1; tp->rx_opt.sack_ok |= 4; MYNET_INC_STATS_BH(LINUX_MIB_TCPDSACKRECV); }else if( num_sacks > 1 && !after(end_seq, ntohl(sp[1].end_seq)) && !before(start_seq, ntohl(sp[1].start_seq))) { dup_sack = 1; tp->rx_opt.sack_ok |= 4; MYNET_INC_STATS_BH(LINUX_MIB_TCPDSACKOFORECV); } if( dup_sack && !after(end_seq, prior_snd_una) && after(end_seq, tp->undo_marker) ) tp->undo_retrans--; if (before(ack, prior_snd_una - tp->max_window)) return 0; } } if (flag) num_sacks = 1; else { int j; tp->fastpath_skb_hint = NULL; for (i = num_sacks-1; i > 0; i--) { for (j = 0; j < i; j++){ if (after(ntohl(sp[j].start_seq), ntohl(sp[j+1].start_seq))){ sp[j].start_seq = htonl(tp->recv_sack_cache[j+1].start_seq); sp[j].end_seq = htonl(tp->recv_sack_cache[j+1].end_seq); sp[j+1].start_seq = htonl(tp->recv_sack_cache[j].start_seq); sp[j+1].end_seq = htonl(tp->recv_sack_cache[j].end_seq); } } } } flag = 0; for (i=0; i<num_sacks; i++, sp++) { struct sk_buff *skb; __u32 start_seq = ntohl(sp->start_seq); __u32 end_seq = ntohl(sp->end_seq); int fack_count; if (tp->fastpath_skb_hint) { skb = tp->fastpath_skb_hint; fack_count = tp->fastpath_cnt_hint; }else{ skb = sk->sk_write_queue.next; fack_count = 0; } if (after(end_seq, tp->high_seq)) flag |= FLAG_DATA_LOST; sk_stream_for_retrans_queue_from(skb, sk) { int in_sack, pcount; u8 sacked; tp->fastpath_skb_hint = skb; tp->fastpath_cnt_hint = fack_count; if (!before(TCP_SKB_CB(skb)->seq, end_seq)) break; in_sack = !after(start_seq, TCP_SKB_CB(skb)->seq) && !before(end_seq, TCP_SKB_CB(skb)->end_seq); pcount = tcp_skb_pcount(skb); if (pcount > 1 && !in_sack && after(TCP_SKB_CB(skb)->end_seq, start_seq)) { unsigned int pkt_len; in_sack = !after(start_seq, TCP_SKB_CB(skb)->seq); if (!in_sack) pkt_len = (start_seq - TCP_SKB_CB(skb)->seq); else pkt_len = (end_seq - TCP_SKB_CB(skb)->seq); if( mytcp_fragment(sk, skb, pkt_len, skb_shinfo(skb)->tso_size) ) break; pcount = tcp_skb_pcount(skb); } fack_count += pcount; sacked = TCP_SKB_CB(skb)->sacked; if( (dup_sack && in_sack) && (sacked & TCPCB_RETRANS) && after(TCP_SKB_CB(skb)->end_seq, tp->undo_marker)) tp->undo_retrans--; if (!after(TCP_SKB_CB(skb)->end_seq, tp->snd_una)) { if( sacked & TCPCB_RETRANS ){ if( (dup_sack && in_sack) && (sacked&TCPCB_SACKED_ACKED) ) reord = min(fack_count, reord); }else{ if (fack_count < prior_fackets && !(sacked&TCPCB_SACKED_ACKED)) reord = min(fack_count, reord); } continue; } if( (sacked & TCPCB_SACKED_RETRANS) && after(end_seq, TCP_SKB_CB(skb)->ack_seq) && (!lost_retrans || after(end_seq, lost_retrans))) lost_retrans = end_seq; if (!in_sack) continue; if( !(sacked&TCPCB_SACKED_ACKED) ){ if( sacked & TCPCB_SACKED_RETRANS ){ if (sacked & TCPCB_LOST) { TCP_SKB_CB(skb)->sacked &= ~(TCPCB_LOST|TCPCB_SACKED_RETRANS); tp->lost_out -= tcp_skb_pcount(skb); tp->retrans_out -= tcp_skb_pcount(skb); tp->retransmit_skb_hint = NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -