⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mytcp_input.c

📁 一个基于linux的TCP/IP协议栈的实现
💻 C
📖 第 1 页 / 共 5 页
字号:
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 + -