📄 tcp.c
字号:
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 + -