TCPプロトコルについて
struct proto tcp_prot = {
.name = "TCP",
.owner = THIS_MODULE,
.close = tcp_close,
.pre_connect = tcp_v4_pre_connect,
.connect = tcp_v4_connect,
.disconnect = tcp_disconnect,
.accept = inet_csk_accept,
.ioctl = tcp_ioctl,
.init = tcp_v4_init_sock,
...
}
TCPプロトコルのconnectは「tcp_v4_connect」関数から始まっているのが分かる
tcp_v4_connect関数
int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
{
...
tcp_set_state(sk, TCP_SYN_SENT);
...
err = tcp_connect(sk);
...
return 0;
...
}
EXPORT_SYMBOL(tcp_v4_connect);
送信ポートや宛先IPなどの処理は端折っていますが、「TCP_SYN_SENT」状態にした上でtcp_connectを行っている。
tcp_connect関数
SYNのパケットの作成、(IPレイヤへ)送信を行うため様々な関数を呼んでいます。
int tcp_connect(struct sock *sk)
{
tcp_connect_init(sk);
buff = tcp_stream_alloc_skb(sk, 0, sk->sk_allocation, true);
tcp_init_nondata_skb(buff, tp->write_seq++, TCPHDR_SYN);
tcp_connect_queue_skb(sk, buff);
tcp_ecn_send_syn(sk, buff);
tcp_rbtree_insert(&sk->tcp_rtx_queue, buff);
/* Send off SYN; include data in Fast Open. */
err = tp->fastopen_req ? tcp_send_syn_data(sk, buff) :
tcp_transmit_skb(sk, buff, 1, sk->sk_allocation);
if (err == -ECONNREFUSED)
return err;
/* Timer for repeating the SYN until an answer. */
inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
inet_csk(sk)->icsk_rto, TCP_RTO_MAX);
return 0;
}
EXPORT_SYMBOL(tcp_connect);
参考文献
https://wiki.bit-hive.com/linuxkernelmemo/pg/IPv4%20%E9%80%81%E4%BF%A1%E5%87%A6%E7%90%86
https://elixir.bootlin.com/linux/latest/source/net/ipv4/tcp_output.c#L3807
https://elixir.bootlin.com/linux/latest/source/include/net/tcp.h#L458