static void tcp_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) {//这里,达到max,丢弃报文 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. */
//复制一份新的sock 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,原来的sk状态仍为LISTEN,这样在下一个tcp_rcv的处理中,会做进一步的处理 newsk->timeout = 0; newsk->send_seq = jiffies * SEQ_TICK - seq_offset;//随机生成序列号算法 newsk->window_seq = newsk->send_seq; newsk->rcv_ack_seq = newsk->send_seq; newsk->urg =0; newsk->retransmits = 0; newsk->destroy = 0; newsk->timer.data = (unsigned long)newsk; newsk->timer.function = &net_timer;//协议用到的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); //准备发送sync&ack的报文 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->send_seq;
/* Swap the send and the receive. */ t1->dest = skb->h.th->source; t1->source = newsk->dummy_th.source; t1->seq = ntohl(newsk->send_seq++); t1->ack = 1;//设置ACK标志 newsk->window = tcp_select_window(newsk);/*newsk->prot->rspace(newsk);*/ t1->window = ntohs(newsk->window); t1->res1 = 0; t1->res2 = 0; t1->rst = 0; t1->urg = 0; t1->psh = 0; t1->syn = 1;//设置SYNC标志 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);//在这里发送SYNC/ACK报文
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);//同时把接收的这个报文上加入到sock接收队列中 sk->ack_backlog++; release_sock(newsk); }
|