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

📄 tcp.c

📁 《嵌入式系统设计与实例开发实验教材二源码》Linux内核移植与编译实验
💻 C
📖 第 1 页 / 共 5 页
字号:
			if (answ && !skb_queue_empty(&sk->receive_queue))				answ -= ((struct sk_buff*)sk->receive_queue.prev)->h.th->fin;		} else			answ = tp->urg_seq - tp->copied_seq;		release_sock(sk);		break;	case SIOCATMARK:		{			answ = tp->urg_data && tp->urg_seq == tp->copied_seq;			break;		}	case SIOCOUTQ:		if (sk->state == TCP_LISTEN)			return(-EINVAL);		if ((1<<sk->state) & (TCPF_SYN_SENT|TCPF_SYN_RECV))			answ = 0;		else			answ = tp->write_seq - tp->snd_una;		break;	default:		return(-ENOIOCTLCMD);	};	return put_user(answ, (int *)arg);}int tcp_listen_start(struct sock *sk){	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);	struct tcp_listen_opt *lopt;	sk->max_ack_backlog = 0;	sk->ack_backlog = 0;	tp->accept_queue = tp->accept_queue_tail = NULL;	tp->syn_wait_lock = RW_LOCK_UNLOCKED;	tcp_delack_init(tp);	lopt = kmalloc(sizeof(struct tcp_listen_opt), GFP_KERNEL);	if (!lopt)		return -ENOMEM;	memset(lopt, 0, sizeof(struct tcp_listen_opt));	for (lopt->max_qlen_log = 6; ; lopt->max_qlen_log++)		if ((1<<lopt->max_qlen_log) >= sysctl_max_syn_backlog)			break;	write_lock_bh(&tp->syn_wait_lock);	tp->listen_opt = lopt;	write_unlock_bh(&tp->syn_wait_lock);	/* There is race window here: we announce ourselves listening,	 * but this transition is still not validated by get_port().	 * It is OK, because this socket enters to hash table only	 * after validation is complete.	 */	sk->state = TCP_LISTEN;	if (sk->prot->get_port(sk, sk->num) == 0) {		sk->sport = htons(sk->num);		sk_dst_reset(sk);		sk->prot->hash(sk);		return 0;	}	sk->state = TCP_CLOSE;	write_lock_bh(&tp->syn_wait_lock);	tp->listen_opt = NULL;	write_unlock_bh(&tp->syn_wait_lock);	kfree(lopt);	return -EADDRINUSE;}/* *	This routine closes sockets which have been at least partially *	opened, but not yet accepted. */static void tcp_listen_stop (struct sock *sk){	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);	struct tcp_listen_opt *lopt = tp->listen_opt;	struct open_request *acc_req = tp->accept_queue;	struct open_request *req;	int i;	tcp_delete_keepalive_timer(sk);	/* make all the listen_opt local to us */	write_lock_bh(&tp->syn_wait_lock);	tp->listen_opt =NULL;	write_unlock_bh(&tp->syn_wait_lock);	tp->accept_queue = tp->accept_queue_tail = NULL;	if (lopt->qlen) {		for (i=0; i<TCP_SYNQ_HSIZE; i++) {			while ((req = lopt->syn_table[i]) != NULL) {				lopt->syn_table[i] = req->dl_next;				lopt->qlen--;				tcp_openreq_free(req);		/* Following specs, it would be better either to send FIN		 * (and enter FIN-WAIT-1, it is normal close)		 * or to send active reset (abort). 		 * Certainly, it is pretty dangerous while synflood, but it is		 * bad justification for our negligence 8)		 * To be honest, we are not able to make either		 * of the variants now.			--ANK		 */			}		}	}	BUG_TRAP(lopt->qlen == 0);	kfree(lopt);	while ((req=acc_req) != NULL) {		struct sock *child = req->sk;		acc_req = req->dl_next;		local_bh_disable();		bh_lock_sock(child);		BUG_TRAP(child->lock.users==0);		sock_hold(child);		tcp_disconnect(child, O_NONBLOCK);		sock_orphan(child);		atomic_inc(&tcp_orphan_count);		tcp_destroy_sock(child);		bh_unlock_sock(child);		local_bh_enable();		sock_put(child);		tcp_acceptq_removed(sk);		tcp_openreq_fastfree(req);	}	BUG_TRAP(sk->ack_backlog == 0);}/* *	Wait for a socket to get into the connected state * *	Note: Must be called with the socket locked. */static int wait_for_tcp_connect(struct sock * sk, int flags, long *timeo_p){	struct task_struct *tsk = current;	DECLARE_WAITQUEUE(wait, tsk);	while((1 << sk->state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) {		if(sk->err)			return sock_error(sk);		if((1 << sk->state) &		   ~(TCPF_SYN_SENT | TCPF_SYN_RECV))			return -EPIPE;		if(!*timeo_p)			return -EAGAIN;		if(signal_pending(tsk))			return sock_intr_errno(*timeo_p);		__set_task_state(tsk, TASK_INTERRUPTIBLE);		add_wait_queue(sk->sleep, &wait);		sk->tp_pinfo.af_tcp.write_pending++;		release_sock(sk);		*timeo_p = schedule_timeout(*timeo_p);		lock_sock(sk);		__set_task_state(tsk, TASK_RUNNING);		remove_wait_queue(sk->sleep, &wait);		sk->tp_pinfo.af_tcp.write_pending--;	}	return 0;}static inline int tcp_memory_free(struct sock *sk){	return sk->wmem_queued < sk->sndbuf;}/* *	Wait for more memory for a socket */static int wait_for_tcp_memory(struct sock * sk, long *timeo){	int err = 0;	long vm_wait = 0;	long current_timeo = *timeo;	DECLARE_WAITQUEUE(wait, current);	if (tcp_memory_free(sk))		current_timeo = vm_wait = (net_random()%(HZ/5))+2;	add_wait_queue(sk->sleep, &wait);	for (;;) {		set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);		set_current_state(TASK_INTERRUPTIBLE);		if (sk->err || (sk->shutdown & SEND_SHUTDOWN))			goto do_error;		if (!*timeo)			goto do_nonblock;		if (signal_pending(current))			goto do_interrupted;		clear_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);		if (tcp_memory_free(sk) && !vm_wait)			break;		set_bit(SOCK_NOSPACE, &sk->socket->flags);		sk->tp_pinfo.af_tcp.write_pending++;		release_sock(sk);		if (!tcp_memory_free(sk) || vm_wait)			current_timeo = schedule_timeout(current_timeo);		lock_sock(sk);		sk->tp_pinfo.af_tcp.write_pending--;		if (vm_wait) {			vm_wait -= current_timeo;			current_timeo = *timeo;			if (current_timeo != MAX_SCHEDULE_TIMEOUT &&			    (current_timeo -= vm_wait) < 0)				current_timeo = 0;			vm_wait = 0;		}		*timeo = current_timeo;	}out:	current->state = TASK_RUNNING;	remove_wait_queue(sk->sleep, &wait);	return err;do_error:	err = -EPIPE;	goto out;do_nonblock:	err = -EAGAIN;	goto out;do_interrupted:	err = sock_intr_errno(*timeo);	goto out;}ssize_t do_tcp_sendpages(struct sock *sk, struct page **pages, int poffset, size_t psize, int flags);static inline intcan_coalesce(struct sk_buff *skb, int i, struct page *page, int off){	if (i) {		skb_frag_t *frag = &skb_shinfo(skb)->frags[i-1];		return page == frag->page &&			off == frag->page_offset+frag->size;	}	return 0;}static inline voidfill_page_desc(struct sk_buff *skb, int i, struct page *page, int off, int size){	skb_frag_t *frag = &skb_shinfo(skb)->frags[i];	frag->page = page;	frag->page_offset = off;	frag->size = size;	skb_shinfo(skb)->nr_frags = i+1;}static inline void tcp_mark_push(struct tcp_opt *tp, struct sk_buff *skb){	TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH;	tp->pushed_seq = tp->write_seq;}static inline int forced_push(struct tcp_opt *tp){	return after(tp->write_seq, tp->pushed_seq + (tp->max_window>>1));}static inline voidskb_entail(struct sock *sk, struct tcp_opt *tp, struct sk_buff *skb){	skb->csum = 0;	TCP_SKB_CB(skb)->seq = tp->write_seq;	TCP_SKB_CB(skb)->end_seq = tp->write_seq;	TCP_SKB_CB(skb)->flags = TCPCB_FLAG_ACK;	TCP_SKB_CB(skb)->sacked = 0;	__skb_queue_tail(&sk->write_queue, skb);	tcp_charge_skb(sk, skb);	if (tp->send_head == NULL)		tp->send_head = skb;}static inline voidtcp_mark_urg(struct tcp_opt *tp, int flags, struct sk_buff *skb){	if (flags & MSG_OOB) {		tp->urg_mode = 1;		tp->snd_up = tp->write_seq;		TCP_SKB_CB(skb)->sacked |= TCPCB_URG;	}}static inline voidtcp_push(struct sock *sk, struct tcp_opt *tp, int flags, int mss_now, int nonagle){	if (tp->send_head) {		struct sk_buff *skb = sk->write_queue.prev;		if (!(flags&MSG_MORE) || forced_push(tp))			tcp_mark_push(tp, skb);		tcp_mark_urg(tp, flags, skb);		__tcp_push_pending_frames(sk, tp, mss_now, (flags&MSG_MORE) ? 2 : nonagle);	}}static int tcp_error(struct sock *sk, int flags, int err){	if (err == -EPIPE)		err = sock_error(sk) ? : -EPIPE;	if (err == -EPIPE && !(flags&MSG_NOSIGNAL))		send_sig(SIGPIPE, current, 0);	return err;}ssize_t do_tcp_sendpages(struct sock *sk, struct page **pages, int poffset, size_t psize, int flags){	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);	int mss_now;	int err;	ssize_t copied;	long timeo = sock_sndtimeo(sk, flags&MSG_DONTWAIT);	/* Wait for a connection to finish. */	if ((1 << sk->state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT))		if((err = wait_for_tcp_connect(sk, 0, &timeo)) != 0)			goto out_err;	clear_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);	mss_now = tcp_current_mss(sk);	copied = 0;	err = -EPIPE;	if (sk->err || (sk->shutdown & SEND_SHUTDOWN))		goto do_error;	while (psize > 0) {		struct sk_buff *skb = sk->write_queue.prev;		int offset, size, copy, i;		struct page *page;		page = pages[poffset/PAGE_SIZE];		offset = poffset % PAGE_SIZE;		size = min_t(size_t, psize, PAGE_SIZE-offset);		if (tp->send_head==NULL || (copy = mss_now - skb->len) <= 0) {new_segment:			if (!tcp_memory_free(sk))				goto wait_for_sndbuf;			skb = tcp_alloc_pskb(sk, 0, tp->mss_cache, sk->allocation);			if (skb == NULL)				goto wait_for_memory;			skb_entail(sk, tp, skb);			copy = mss_now;		}		if (copy > size)			copy = size;		i = skb_shinfo(skb)->nr_frags;		if (can_coalesce(skb, i, page, offset)) {			skb_shinfo(skb)->frags[i-1].size += copy;		} else if (i < MAX_SKB_FRAGS) {			get_page(page);			fill_page_desc(skb, i, page, offset, copy);		} else {			tcp_mark_push(tp, skb);			goto new_segment;		}		skb->len += copy;		skb->data_len += copy;		skb->ip_summed = CHECKSUM_HW;		tp->write_seq += copy;		TCP_SKB_CB(skb)->end_seq += copy;		if (!copied)			TCP_SKB_CB(skb)->flags &= ~TCPCB_FLAG_PSH;		copied += copy;		poffset += copy;		if (!(psize -= copy))			goto out;		if (skb->len != mss_now || (flags&MSG_OOB))			continue;		if (forced_push(tp)) {			tcp_mark_push(tp, skb);			__tcp_push_pending_frames(sk, tp, mss_now, 1);		} else if (skb == tp->send_head)			tcp_push_one(sk, mss_now);		continue;wait_for_sndbuf:		set_bit(SOCK_NOSPACE, &sk->socket->flags);wait_for_memory:		if (copied)			tcp_push(sk, tp, flags&~MSG_MORE, mss_now, 1);		if ((err = wait_for_tcp_memory(sk, &timeo)) != 0)			goto do_error;		mss_now = tcp_current_mss(sk);	}out:	if (copied)		tcp_push(sk, tp, flags, mss_now, tp->nonagle);	return copied;do_error:	if (copied)		goto out;out_err:	return tcp_error(sk, flags, err);}ssize_t tcp_sendpage(struct socket *sock, struct page *page, int offset, size_t size, int flags){	ssize_t res;	struct sock *sk = sock->sk;#define TCP_ZC_CSUM_FLAGS (NETIF_F_IP_CSUM|NETIF_F_NO_CSUM|NETIF_F_HW_CSUM)	if (!(sk->route_caps & NETIF_F_SG) || 	    !(sk->route_caps & TCP_ZC_CSUM_FLAGS))		return sock_no_sendpage(sock, page, offset, size, flags);#undef TCP_ZC_CSUM_FLAGS	lock_sock(sk);	TCP_CHECK_TIMER(sk);	res = do_tcp_sendpages(sk, &page, offset, size, flags);	TCP_CHECK_TIMER(sk);	release_sock(sk);	return res;}#define TCP_PAGE(sk)	(sk->tp_pinfo.af_tcp.sndmsg_page)#define TCP_OFF(sk)	(sk->tp_pinfo.af_tcp.sndmsg_off)static inline inttcp_copy_to_page(struct sock *sk, char *from, struct sk_buff *skb,		 struct page *page, int off, int copy){	int err = 0;	unsigned int csum;	csum = csum_and_copy_from_user(from, page_address(page)+off,				       copy, 0, &err);	if (!err) {		if (skb->ip_summed == CHECKSUM_NONE)			skb->csum = csum_block_add(skb->csum, csum, skb->len);		skb->len += copy;		skb->data_len += copy;		skb->truesize += copy;		sk->wmem_queued += copy;		sk->forward_alloc -= copy;	}	return err;}static inline intskb_add_data(struct sk_buff *skb, char *from, int copy){	int err = 0;	unsigned int csum;	int off = skb->len;	csum = csum_and_copy_from_user(from, skb_put(skb, copy),				       copy, 0, &err);	if (!err) {		skb->csum = csum_block_add(skb->csum, csum, off);		return 0;	}	__skb_trim(skb, off);	return -EFAULT;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -