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

📄 tcp.c

📁 LINUX1.0内核源代码,学习LINUX编程的一定要看。
💻 C
📖 第 1 页 / 共 5 页
字号:
		}	case TIOCOUTQ:		{			unsigned long amount;			if (sk->state == TCP_LISTEN) return(-EINVAL);			amount = sk->prot->wspace(sk);			err=verify_area(VERIFY_WRITE,(void *)arg,						   sizeof(unsigned long));			if(err)				return err;			put_fs_long(amount,(unsigned long *)arg);			return(0);		}	default:		return(-EINVAL);  }}/* This routine computes a TCP checksum. */unsigned shorttcp_check(struct tcphdr *th, int len,	  unsigned long saddr, unsigned long daddr){       unsigned long sum;     if (saddr == 0) saddr = my_addr();  print_th(th);  __asm__("\t addl %%ecx,%%ebx\n"	  "\t adcl %%edx,%%ebx\n"	  "\t adcl $0, %%ebx\n"	  : "=b"(sum)	  : "0"(daddr), "c"(saddr), "d"((ntohs(len) << 16) + IPPROTO_TCP*256)	  : "cx","bx","dx" );     if (len > 3) {	__asm__("\tclc\n"		"1:\n"		"\t lodsl\n"		"\t adcl %%eax, %%ebx\n"		"\t loop 1b\n"		"\t adcl $0, %%ebx\n"		: "=b"(sum) , "=S"(th)		: "0"(sum), "c"(len/4) ,"1"(th)		: "ax", "cx", "bx", "si" );  }     /* Convert from 32 bits to 16 bits. */  __asm__("\t movl %%ebx, %%ecx\n"	  "\t shrl $16,%%ecx\n"	  "\t addw %%cx, %%bx\n"	  "\t adcw $0, %%bx\n"	  : "=b"(sum)	  : "0"(sum)	  : "bx", "cx");     /* Check for an extra word. */  if ((len & 2) != 0) {	__asm__("\t lodsw\n"		"\t addw %%ax,%%bx\n"		"\t adcw $0, %%bx\n"		: "=b"(sum), "=S"(th)		: "0"(sum) ,"1"(th)		: "si", "ax", "bx");  }     /* Now check for the extra byte. */  if ((len & 1) != 0) {	__asm__("\t lodsb\n"		"\t movb $0,%%ah\n"		"\t addw %%ax,%%bx\n"		"\t adcw $0, %%bx\n"		: "=b"(sum)		: "0"(sum) ,"S"(th)		: "si", "ax", "bx");  }     /* We only want the bottom 16 bits, but we never cleared the top 16. */  return((~sum) & 0xffff);}void tcp_send_check(struct tcphdr *th, unsigned long saddr, 		unsigned long daddr, int len, struct sock *sk){	th->check = 0;	th->check = tcp_check(th, len, saddr, daddr);	return;}static void tcp_send_skb(struct sock *sk, struct sk_buff *skb){	int size;	struct tcphdr * th = skb->h.th;	/* length of packet (not counting length of pre-tcp headers) */	size = skb->len - ((unsigned char *) th - skb->data);	/* sanity check it.. */	if (size < sizeof(struct tcphdr) || size > skb->len) {		printk("tcp_send_skb: bad skb (skb = %p, data = %p, th = %p, len = %lu)\n",			skb, skb->data, th, skb->len);		kfree_skb(skb, FREE_WRITE);		return;	}	/* If we have queued a header size packet.. */	if (size == sizeof(struct tcphdr)) {		/* If its got a syn or fin its notionally included in the size..*/		if(!th->syn && !th->fin) {			printk("tcp_send_skb: attempt to queue a bogon.\n");			kfree_skb(skb,FREE_WRITE);			return;		}	}  	/* We need to complete and send the packet. */	tcp_send_check(th, sk->saddr, sk->daddr, size, sk);	skb->h.seq = ntohl(th->seq) + size - 4*th->doff;	if (after(skb->h.seq, sk->window_seq) ||	    (sk->retransmits && sk->timeout == TIME_WRITE) ||	     sk->packets_out >= sk->cong_window) {		DPRINTF((DBG_TCP, "sk->cong_window = %d, sk->packets_out = %d\n",					sk->cong_window, sk->packets_out));		DPRINTF((DBG_TCP, "sk->write_seq = %d, sk->window_seq = %d\n",					sk->write_seq, sk->window_seq));		skb->next = NULL;		skb->magic = TCP_WRITE_QUEUE_MAGIC;		if (sk->wback == NULL) {			sk->wfront = skb;		} else {			sk->wback->next = skb;		}		sk->wback = skb;		if (before(sk->window_seq, sk->wfront->h.seq) &&		    sk->send_head == NULL &&		    sk->ack_backlog == 0)		  reset_timer(sk, TIME_PROBE0, sk->rto);	} else {		sk->sent_seq = sk->write_seq;		sk->prot->queue_xmit(sk, skb->dev, skb, 0);	}}struct sk_buff * tcp_dequeue_partial(struct sock * sk){	struct sk_buff * skb;	unsigned long flags;	save_flags(flags);	cli();	skb = sk->partial;	if (skb) {		sk->partial = NULL;		del_timer(&sk->partial_timer);	}	restore_flags(flags);	return skb;}static void tcp_send_partial(struct sock *sk){	struct sk_buff *skb;	if (sk == NULL)		return;	while ((skb = tcp_dequeue_partial(sk)) != NULL)		tcp_send_skb(sk, skb);}void tcp_enqueue_partial(struct sk_buff * skb, struct sock * sk){	struct sk_buff * tmp;	unsigned long flags;	save_flags(flags);	cli();	tmp = sk->partial;	if (tmp)		del_timer(&sk->partial_timer);	sk->partial = skb;	sk->partial_timer.expires = HZ;	sk->partial_timer.function = (void (*)(unsigned long)) tcp_send_partial;	sk->partial_timer.data = (unsigned long) sk;	add_timer(&sk->partial_timer);	restore_flags(flags);	if (tmp)		tcp_send_skb(sk, tmp);}/* This routine sends an ack and also updates the window. */static voidtcp_send_ack(unsigned long sequence, unsigned long ack,	     struct sock *sk,	     struct tcphdr *th, unsigned long daddr){  struct sk_buff *buff;  struct tcphdr *t1;  struct device *dev = NULL;  int tmp;  if(sk->zapped)	return;		/* We have been reset, we may not send again */  /*   * We need to grab some memory, and put together an ack,   * and then put it into the queue to be sent.   */  buff = sk->prot->wmalloc(sk, MAX_ACK_SIZE, 1, GFP_ATOMIC);  if (buff == NULL) {	/* Force it to send an ack. */	sk->ack_backlog++;	if (sk->timeout != TIME_WRITE && tcp_connected(sk->state)) {		reset_timer(sk, TIME_WRITE, 10);	}if (inet_debug == DBG_SLIP) printk("\rtcp_ack: malloc failed\n");	return;  }  buff->mem_addr = buff;  buff->mem_len = MAX_ACK_SIZE;  buff->len = sizeof(struct tcphdr);  buff->sk = sk;  t1 =(struct tcphdr *) buff->data;  /* Put in the IP header and routing stuff. */  tmp = sk->prot->build_header(buff, sk->saddr, daddr, &dev,				IPPROTO_TCP, sk->opt, MAX_ACK_SIZE,sk->ip_tos,sk->ip_ttl);  if (tmp < 0) {  	buff->free=1;	sk->prot->wfree(sk, buff->mem_addr, buff->mem_len);if (inet_debug == DBG_SLIP) printk("\rtcp_ack: build_header failed\n");	return;  }  buff->len += tmp;  t1 =(struct tcphdr *)((char *)t1 +tmp);  /* FIXME: */  memcpy(t1, th, sizeof(*t1)); /* this should probably be removed */  /* swap the send and the receive. */  t1->dest = th->source;  t1->source = th->dest;  t1->seq = ntohl(sequence);  t1->ack = 1;  sk->window = tcp_select_window(sk);/*sk->prot->rspace(sk);*/  t1->window = ntohs(sk->window);  t1->res1 = 0;  t1->res2 = 0;  t1->rst = 0;  t1->urg = 0;  t1->syn = 0;  t1->psh = 0;  t1->fin = 0;  if (ack == sk->acked_seq) {	sk->ack_backlog = 0;	sk->bytes_rcv = 0;	sk->ack_timed = 0;	if (sk->send_head == NULL && sk->wfront == NULL && sk->timeout == TIME_WRITE) 	{		if(sk->keepopen)			reset_timer(sk,TIME_KEEPOPEN,TCP_TIMEOUT_LEN);		else			delete_timer(sk);	}  }  t1->ack_seq = ntohl(ack);  t1->doff = sizeof(*t1)/4;  tcp_send_check(t1, sk->saddr, daddr, sizeof(*t1), sk);  if (sk->debug)  	 printk("\rtcp_ack: seq %lx ack %lx\n", sequence, ack);  sk->prot->queue_xmit(sk, dev, buff, 1);}/* This routine builds a generic TCP header. */static inttcp_build_header(struct tcphdr *th, struct sock *sk, int push){  /* FIXME: want to get rid of this. */  memcpy(th,(void *) &(sk->dummy_th), sizeof(*th));  th->seq = htonl(sk->write_seq);  th->psh =(push == 0) ? 1 : 0;  th->doff = sizeof(*th)/4;  th->ack = 1;  th->fin = 0;  sk->ack_backlog = 0;  sk->bytes_rcv = 0;  sk->ack_timed = 0;  th->ack_seq = htonl(sk->acked_seq);  sk->window = tcp_select_window(sk)/*sk->prot->rspace(sk)*/;  th->window = htons(sk->window);  return(sizeof(*th));}/* * This routine copies from a user buffer into a socket, * and starts the transmit system. */static inttcp_write(struct sock *sk, unsigned char *from,	  int len, int nonblock, unsigned flags){  int copied = 0;  int copy;  int tmp;  struct sk_buff *skb;  struct sk_buff *send_tmp;  unsigned char *buff;  struct proto *prot;  struct device *dev = NULL;  DPRINTF((DBG_TCP, "tcp_write(sk=%X, from=%X, len=%d, nonblock=%d, flags=%X)\n",					sk, from, len, nonblock, flags));  sk->inuse=1;  prot = sk->prot;  while(len > 0) {	if (sk->err) {			/* Stop on an error */		release_sock(sk);		if (copied) return(copied);		tmp = -sk->err;		sk->err = 0;		return(tmp);	}	/* First thing we do is make sure that we are established. */	 	if (sk->shutdown & SEND_SHUTDOWN) {		release_sock(sk);		sk->err = EPIPE;		if (copied) return(copied);		sk->err = 0;		return(-EPIPE);	}	/* Wait for a connection to finish. */		while(sk->state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT) {		if (sk->err) {			release_sock(sk);			if (copied) return(copied);			tmp = -sk->err;			sk->err = 0;			return(tmp);		}		if (sk->state != TCP_SYN_SENT && sk->state != TCP_SYN_RECV) {			release_sock(sk);			DPRINTF((DBG_TCP, "tcp_write: return 1\n"));			if (copied) return(copied);			if (sk->err) {				tmp = -sk->err;				sk->err = 0;				return(tmp);			}			if (sk->keepopen) {				send_sig(SIGPIPE, current, 0);			}			return(-EPIPE);		}		if (nonblock || copied) {			release_sock(sk);			DPRINTF((DBG_TCP, "tcp_write: return 2\n"));			if (copied) return(copied);			return(-EAGAIN);		}		release_sock(sk);		cli();		if (sk->state != TCP_ESTABLISHED &&		    sk->state != TCP_CLOSE_WAIT && sk->err == 0) {			interruptible_sleep_on(sk->sleep);			if (current->signal & ~current->blocked) {				sti();				DPRINTF((DBG_TCP, "tcp_write: return 3\n"));				if (copied) return(copied);				return(-ERESTARTSYS);			}		}		sk->inuse = 1;		sti();	}/* * The following code can result in copy <= if sk->mss is ever * decreased.  It shouldn't be.  sk->mss is min(sk->mtu, sk->max_window). * sk->mtu is constant once SYN processing is finished.  I.e. we * had better not get here until we've seen his SYN and at least one * valid ack.  (The SYN sets sk->mtu and the ack sets sk->max_window.) * But ESTABLISHED should guarantee that.  sk->max_window is by definition * non-decreasing.  Note that any ioctl to set user_mss must be done * before the exchange of SYN's.  If the initial ack from the other * end has a window of 0, max_window and thus mss will both be 0. */	/* Now we need to check if we have a half built packet. */	if ((skb = tcp_dequeue_partial(sk)) != NULL) {	        int hdrlen;	         /* IP header + TCP header */		hdrlen = ((unsigned long)skb->h.th - (unsigned long)skb->data)		         + sizeof(struct tcphdr);		/* Add more stuff to the end of skb->len */		if (!(flags & MSG_OOB)) {			copy = min(sk->mss - (skb->len - hdrlen), len);			/* FIXME: this is really a bug. */			if (copy <= 0) {			  printk("TCP: **bug**: \"copy\" <= 0!!\n");			  copy = 0;			}	  			memcpy_fromfs(skb->data + skb->len, from, copy);			skb->len += copy;			from += copy;			copied += copy;			len -= copy;			sk->write_seq += copy;		      }		if ((skb->len - hdrlen) >= sk->mss ||		    (flags & MSG_OOB) ||		    !sk->packets_out)			tcp_send_skb(sk, skb);		else			tcp_enqueue_partial(skb, sk);		continue;	}	/*	 * We also need to worry about the window. 	 * If window < 1/2 the maximum window we've seen from this 	 *   host, don't use it.  This is sender side 	 *   silly window prevention, as specified in RFC1122. 	 *   (Note that this is diffferent than earlier versions of 	 *   SWS prevention, e.g. RFC813.).  What we actually do is 	 *   use the whole MSS.  Since the results in the right	 *   edge of the packet being outside the window, it will	 *   be queued for later rather than sent.	 */	copy = sk->window_seq - sk->write_seq;	if (copy <= 0 || copy < (sk->max_window >> 1) || copy > sk->mss)		copy = sk->mss;	if (copy > len)		copy = len;  /* We should really check the window here also. */	send_tmp = NULL;	if (copy < sk->mss && !(flags & MSG_OOB)) {	/* We will release the socket incase we sleep here. */	  release_sock(sk);	  /* NB: following must be mtu, because mss can be increased.	   * mss is always <= mtu */	  skb = prot->wmalloc(sk, sk->mtu + 128 + prot->max_header + sizeof(*skb), 0, GFP_KERNEL);	  sk->inuse = 1;	  send_tmp = skb;	} else {		/* We will release the socket incase we sleep here. */	  release_sock(sk);	  skb = prot->wmalloc(sk, copy + prot->max_header + sizeof(*skb), 0, GFP_KERNEL);	  sk->inuse = 1;	}	/* If we didn't get any memory, we need to sleep. */	if (skb == NULL) {		if (nonblock /* || copied */) {			release_sock(sk);			DPRINTF((DBG_TCP, "tcp_write: return 4\n"));			if (copied) return(copied);			return(-EAGAIN);		}		/* FIXME: here is another race condition. */		tmp = sk->wmem_alloc;		release_sock(sk);		cli();		/* Again we will try to avoid it. */		if (tmp <= sk->wmem_alloc &&		  (sk->state == TCP_ESTABLISHED||sk->state == TCP_CLOSE_WAIT)				&& sk->err == 0) {			interruptible_sleep_on(sk->sleep);			if (current->signal & ~current->blocked) {				sti();				DPRINTF((DBG_TCP, "tcp_write: return 5\n"));				if (copied) return(copied);				return(-ERESTARTSYS);			}		}		sk->inuse = 1;		sti();		continue;	}

⌨️ 快捷键说明

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