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

📄 tcp.c

📁 LINUX1.0内核源代码,学习LINUX编程的一定要看。
💻 C
📖 第 1 页 / 共 5 页
字号:
  t1->seq = ntohl(sk->write_seq);  sk->write_seq++;  buff->h.seq = sk->write_seq;  t1->ack = 1;  t1->ack_seq = ntohl(sk->acked_seq);  t1->window = ntohs(sk->window=tcp_select_window(sk)/*sk->prot->rspace(sk)*/);  t1->fin = 1;  t1->rst = 0;  t1->doff = sizeof(*t1)/4;  tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk);  /*   * Can't just queue this up.   * It should go at the end of the write queue.   */  if (sk->wback != NULL) {  	buff->free=0;		buff->next = NULL;	sk->wback->next = buff;	sk->wback = buff;	buff->magic = TCP_WRITE_QUEUE_MAGIC;  } else {        sk->sent_seq = sk->write_seq;	sk->prot->queue_xmit(sk, dev, buff, 0);  }  if (sk->state == TCP_ESTABLISHED) sk->state = TCP_FIN_WAIT1;    else sk->state = TCP_FIN_WAIT2;  release_sock(sk);}static inttcp_recvfrom(struct sock *sk, unsigned char *to,	     int to_len, int nonblock, unsigned flags,	     struct sockaddr_in *addr, int *addr_len){  struct sockaddr_in sin;  int len;  int err;  int result;    /* Have to check these first unlike the old code. If      we check them after we lose data on an error     which is wrong */  err = verify_area(VERIFY_WRITE,addr_len,sizeof(long));  if(err)  	return err;  len = get_fs_long(addr_len);  if(len > sizeof(sin))  	len = sizeof(sin);  err=verify_area(VERIFY_WRITE, addr, len);    if(err)  	return err;  	  result=tcp_read(sk, to, to_len, nonblock, flags);  if (result < 0) return(result);    sin.sin_family = AF_INET;  sin.sin_port = sk->dummy_th.dest;  sin.sin_addr.s_addr = sk->daddr;  memcpy_tofs(addr, &sin, len);  put_fs_long(len, addr_len);  return(result);}/* This routine will send an RST to the other tcp. */static voidtcp_reset(unsigned long saddr, unsigned long daddr, struct tcphdr *th,	  struct proto *prot, struct options *opt, struct device *dev, int tos, int ttl){  struct sk_buff *buff;  struct tcphdr *t1;  int tmp;  /*   * We need to grab some memory, and put together an RST,   * and then put it into the queue to be sent.   */  buff = prot->wmalloc(NULL, MAX_RESET_SIZE, 1, GFP_ATOMIC);  if (buff == NULL)   	return;  DPRINTF((DBG_TCP, "tcp_reset buff = %X\n", buff));  buff->mem_addr = buff;  buff->mem_len = MAX_RESET_SIZE;  buff->len = sizeof(*t1);  buff->sk = NULL;  buff->dev = dev;  t1 =(struct tcphdr *) buff->data;  /* Put in the IP header and routing stuff. */  tmp = prot->build_header(buff, saddr, daddr, &dev, IPPROTO_TCP, opt,			   sizeof(struct tcphdr),tos,ttl);  if (tmp < 0) {  	buff->free = 1;	prot->wfree(NULL, buff->mem_addr, buff->mem_len);	return;  }  t1 =(struct tcphdr *)((char *)t1 +tmp);  buff->len += tmp;  memcpy(t1, th, sizeof(*t1));  /* Swap the send and the receive. */  t1->dest = th->source;  t1->source = th->dest;  t1->rst = 1;    t1->window = 0;    if(th->ack)  {  	t1->ack = 0;  	t1->seq = th->ack_seq;  	t1->ack_seq = 0;  }  else  {  	t1->ack = 1;  	if(!th->syn)  		t1->ack_seq=htonl(th->seq);  	else  		t1->ack_seq=htonl(th->seq+1);  	t1->seq=0;  }  t1->syn = 0;  t1->urg = 0;  t1->fin = 0;  t1->psh = 0;  t1->doff = sizeof(*t1)/4;  tcp_send_check(t1, saddr, daddr, sizeof(*t1), NULL);  prot->queue_xmit(NULL, dev, buff, 1);}/* *	Look for tcp options. Parses everything but only knows about MSS. *      This routine is always called with the packet containing the SYN. *      However it may also be called with the ack to the SYN.  So you *      can't assume this is always the SYN.  It's always called after *      we have set up sk->mtu to our own MTU. */ static voidtcp_options(struct sock *sk, struct tcphdr *th){  unsigned char *ptr;  int length=(th->doff*4)-sizeof(struct tcphdr);  int mss_seen = 0;      ptr = (unsigned char *)(th + 1);    while(length>0)  {  	int opcode=*ptr++;  	int opsize=*ptr++;  	switch(opcode)  	{  		case TCPOPT_EOL:  			return;  		case TCPOPT_NOP:  			length-=2;  			continue;  		  		default:  			if(opsize<=2)	/* Avoid silly options looping forever */  				return;  			switch(opcode)  			{  				case TCPOPT_MSS:  					if(opsize==4 && th->syn)  					{  						sk->mtu=min(sk->mtu,ntohs(*(unsigned short *)ptr));						mss_seen = 1;  					}  					break;  				/* Add other options here as people feel the urge to implement stuff like large windows */  			}  			ptr+=opsize-2;  			length-=opsize;  	}  }  if (th->syn) {    if (! mss_seen)      sk->mtu=min(sk->mtu, 536);  /* default MSS if none sent */  }  sk->mss = min(sk->max_window, sk->mtu);}static inline unsigned long default_mask(unsigned long dst){	dst = ntohl(dst);	if (IN_CLASSA(dst))		return htonl(IN_CLASSA_NET);	if (IN_CLASSB(dst))		return htonl(IN_CLASSB_NET);	return htonl(IN_CLASSC_NET);}/* * This routine handles a connection request. * It should make sure we haven't already responded. * Because of the way BSD works, we have to send a syn/ack now. * This also means it will be harder to close a socket which is * listening. */static voidtcp_conn_request(struct sock *sk, struct sk_buff *skb,		 unsigned long daddr, unsigned long saddr,		 struct options *opt, struct device *dev){  struct sk_buff *buff;  struct tcphdr *t1;  unsigned char *ptr;  struct sock *newsk;  struct tcphdr *th;  int tmp;  DPRINTF((DBG_TCP, "tcp_conn_request(sk = %X, skb = %X, daddr = %X, sadd4= %X, \n"	  "                  opt = %X, dev = %X)\n",	  sk, skb, daddr, saddr, opt, dev));    th = skb->h.th;  /* If the socket is dead, don't accept the connection. */  if (!sk->dead) {  	sk->data_ready(sk,0);  } else {	DPRINTF((DBG_TCP, "tcp_conn_request on dead socket\n"));	tcp_reset(daddr, saddr, th, sk->prot, opt, dev, sk->ip_tos,sk->ip_ttl);	kfree_skb(skb, FREE_READ);	return;  }  /*   * Make sure we can accept more.  This will prevent a   * flurry of syns from eating up all our memory.   */  if (sk->ack_backlog >= sk->max_ack_backlog) {	kfree_skb(skb, FREE_READ);	return;  }  /*   * We need to build a new sock struct.   * It is sort of bad to have a socket without an inode attached   * to it, but the wake_up's will just wake up the listening socket,   * and if the listening socket is destroyed before this is taken   * off of the queue, this will take care of it.   */  newsk = (struct sock *) kmalloc(sizeof(struct sock), GFP_ATOMIC);  if (newsk == NULL) {	/* just ignore the syn.  It will get retransmitted. */	kfree_skb(skb, FREE_READ);	return;  }  DPRINTF((DBG_TCP, "newsk = %X\n", newsk));  memcpy((void *)newsk,(void *)sk, sizeof(*newsk));  newsk->wback = NULL;  newsk->wfront = NULL;  newsk->rqueue = NULL;  newsk->send_head = NULL;  newsk->send_tail = NULL;  newsk->back_log = NULL;  newsk->rtt = TCP_CONNECT_TIME << 3;  newsk->rto = TCP_CONNECT_TIME;  newsk->mdev = 0;  newsk->max_window = 0;  newsk->cong_window = 1;  newsk->cong_count = 0;  newsk->ssthresh = 0;  newsk->backoff = 0;  newsk->blog = 0;  newsk->intr = 0;  newsk->proc = 0;  newsk->done = 0;  newsk->partial = NULL;  newsk->pair = NULL;  newsk->wmem_alloc = 0;  newsk->rmem_alloc = 0;  newsk->max_unacked = MAX_WINDOW - TCP_WINDOW_DIFF;  newsk->err = 0;  newsk->shutdown = 0;  newsk->ack_backlog = 0;  newsk->acked_seq = skb->h.th->seq+1;  newsk->fin_seq = skb->h.th->seq;  newsk->copied_seq = skb->h.th->seq;  newsk->state = TCP_SYN_RECV;  newsk->timeout = 0;  newsk->write_seq = jiffies * SEQ_TICK - seq_offset;  newsk->window_seq = newsk->write_seq;  newsk->rcv_ack_seq = newsk->write_seq;  newsk->urg_data = 0;  newsk->retransmits = 0;  newsk->destroy = 0;  newsk->timer.data = (unsigned long)newsk;  newsk->timer.function = &net_timer;  newsk->dummy_th.source = skb->h.th->dest;  newsk->dummy_th.dest = skb->h.th->source;  /* Swap these two, they are from our point of view. */  newsk->daddr = saddr;  newsk->saddr = daddr;  put_sock(newsk->num,newsk);  newsk->dummy_th.res1 = 0;  newsk->dummy_th.doff = 6;  newsk->dummy_th.fin = 0;  newsk->dummy_th.syn = 0;  newsk->dummy_th.rst = 0;  newsk->dummy_th.psh = 0;  newsk->dummy_th.ack = 0;  newsk->dummy_th.urg = 0;  newsk->dummy_th.res2 = 0;  newsk->acked_seq = skb->h.th->seq + 1;  newsk->copied_seq = skb->h.th->seq;  /* Grab the ttl and tos values and use them */  newsk->ip_ttl=sk->ip_ttl;  newsk->ip_tos=skb->ip_hdr->tos;/* use 512 or whatever user asked for *//* note use of sk->user_mss, since user has no direct access to newsk */  if (sk->user_mss)    newsk->mtu = sk->user_mss;  else {#ifdef SUBNETSARELOCAL    if ((saddr ^ daddr) & default_mask(saddr))#else    if ((saddr ^ daddr) & dev->pa_mask)#endif      newsk->mtu = 576 - HEADER_SIZE;    else      newsk->mtu = MAX_WINDOW;  }/* but not bigger than device MTU */  newsk->mtu = min(newsk->mtu, dev->mtu - HEADER_SIZE);/* this will min with what arrived in the packet */  tcp_options(newsk,skb->h.th);  buff = newsk->prot->wmalloc(newsk, MAX_SYN_SIZE, 1, GFP_ATOMIC);  if (buff == NULL) {	sk->err = -ENOMEM;	newsk->dead = 1;	release_sock(newsk);	kfree_skb(skb, FREE_READ);	return;  }    buff->mem_addr = buff;  buff->mem_len = MAX_SYN_SIZE;  buff->len = sizeof(struct tcphdr)+4;  buff->sk = newsk;    t1 =(struct tcphdr *) buff->data;  /* Put in the IP header and routing stuff. */  tmp = sk->prot->build_header(buff, newsk->saddr, newsk->daddr, &dev,			       IPPROTO_TCP, NULL, MAX_SYN_SIZE,sk->ip_tos,sk->ip_ttl);  /* Something went wrong. */  if (tmp < 0) {	sk->err = tmp;	buff->free=1;	kfree_skb(buff,FREE_WRITE);	newsk->dead = 1;	release_sock(newsk);	skb->sk = sk;	kfree_skb(skb, FREE_READ);	return;  }  buff->len += tmp;  t1 =(struct tcphdr *)((char *)t1 +tmp);    memcpy(t1, skb->h.th, sizeof(*t1));  buff->h.seq = newsk->write_seq;  /* Swap the send and the receive. */  t1->dest = skb->h.th->source;  t1->source = newsk->dummy_th.source;  t1->seq = ntohl(newsk->write_seq++);  t1->ack = 1;  newsk->window = tcp_select_window(newsk);/*newsk->prot->rspace(newsk);*/  newsk->sent_seq = newsk->write_seq;  t1->window = ntohs(newsk->window);  t1->res1 = 0;  t1->res2 = 0;  t1->rst = 0;  t1->urg = 0;  t1->psh = 0;  t1->syn = 1;  t1->ack_seq = ntohl(skb->h.th->seq+1);  t1->doff = sizeof(*t1)/4+1;  ptr =(unsigned char *)(t1+1);  ptr[0] = 2;  ptr[1] = 4;  ptr[2] = ((newsk->mtu) >> 8) & 0xff;  ptr[3] =(newsk->mtu) & 0xff;  tcp_send_check(t1, daddr, saddr, sizeof(*t1)+4, newsk);  newsk->prot->queue_xmit(newsk, dev, buff, 0);  reset_timer(newsk, TIME_WRITE /* -1 ? FIXME ??? */, TCP_CONNECT_TIME);  skb->sk = newsk;  /* Charge the sock_buff to newsk. */  sk->rmem_alloc -= skb->mem_len;  newsk->rmem_alloc += skb->mem_len;  skb_queue_tail(&sk->rqueue,skb);  sk->ack_backlog++;  release_sock(newsk);}static voidtcp_close(struct sock *sk, int timeout){  struct sk_buff *buff;  int need_reset = 0;  struct tcphdr *t1, *th;  struct proto *prot;  struct device *dev=NULL;  int tmp;  /*   * We need to grab some memory, and put together a FIN,   * and then put it into the queue to be sent.   */  DPRINTF((DBG_TCP, "tcp_close((struct sock *)%X, %d)\n",sk, timeout));  sk->inuse = 1;  sk->keepopen = 1;  sk->shutdown = SHUTDOWN_MASK;  if (!sk->dead)   	sk->state_change(sk);  /* We need to flush the recv. buffs. */  if (skb_peek(&sk->rqueue) != NULL)   {	struct sk_buff *skb;	if(sk->debug)		printk("Clean rcv queue\n");	while((skb=skb_dequeue(&sk->rqueue))!=NULL)	{		if(skb->len > 0 && after(skb->h.th->seq + skb->len + 1 , sk->copied_seq))				need_reset = 1;		kfree_skb(skb, FREE_READ);	}	if(sk->debug)		printk("Cleaned.\n");  }  sk->rqueue = NULL;  /* Get rid off any half-completed packets. */  if (sk->partial) {	tcp_send_partial(sk);  }  switch(sk->state) {	case TCP_FIN_WAIT1:	case TCP_FIN_WAIT2:	case TCP_LAST_ACK:		/* start a timer. */                /* original code was 4 * sk->rtt.  In converting to the		 * new rtt representation, we can't quite use that.		 * it seems to make most sense to  use the backed off value		 */		reset_timer(sk, TIME_CLOSE, 4 * sk->rto);		if (timeout) tcp_time_wait(sk);		release_sock(sk);		return;	/* break causes a double release - messy */	case TCP_TIME_WAIT:		if (timeout) {		  sk->state = TCP_CLOSE;		}		release_sock(sk);		return;	case TCP_LISTEN:		sk->state = TCP_CLOSE;		release_sock(sk);		return;	case TCP_CLOSE:		release_sock(sk);		return;	case TCP_CLOSE_WAIT:	case TCP_ESTABLISHED:	case TCP_SYN_SENT:	case TCP_SYN_RECV:

⌨️ 快捷键说明

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