asmlinkage long sys_socket(int family, int type, int protocol)			: PF_INET6(= 10), SOCK_STREAM(= 1), IPPROTO_TCP(= 6)
{
	int retval;
	struct socket *sock;
- retval = sock_create(family, type, protocol, &sock);
- if (retval < 0) goto out;
- retval = sock_map_fd(sock);							:  FD ä sock ȥޥåԥ󥰤롣
- if (retval < 0) goto out_release;

out:
	/* It may be already another descriptor 8) Not kernel problem. */
- return retval;
out_release:
- sock_release(sock);
- return retval;
}

int sock_create(int family, int type, int protocol, struct socket **res)
{
	int i;
	struct socket *sock;
- if (family < 0 || family >= NPROTO) return -EAFNOSUPPORT;			: NPROTO = 32
- if (type < 0 || type >= SOCK_MAX) return -EINVAL;				: SOCK_MAX = SOCK_PACKET(=10) + 1
	/* Compatibility.
	   This uglymoron is moved from INET layer to here to avoid
	   deadlock in module load.	 */
- if (family == PF_INET && type == SOCK_PACKET) {				: PF_INET = AF_INET(= 2)
		static int warned; 
  - if (!warned) {
    - warned = 1;
    - printk(KERN_INFO "%s uses obsolete (PF_INET,SOCK_PACKET)\n", current->comm);
  - }
  - family = PF_PACKET;
- }

#if defined(CONFIG_KMOD) && defined(CONFIG_NET)
	/* Attempt to load a protocol module if the find failed. 
	 * 12/09/1996 Marcin: But! this makes REALLY only sense, if the user 
	 * requested real, full-featured networking support upon configuration.
	 * Otherwise module support will break!	 */
- if (net_families[family]==NULL)
- {
  - char module_name[30];
  - sprintf(module_name,"net-pf-%d",family);
  - request_module(module_name);
- }
#endif
- net_family_read_lock();
- if (net_families[family] == NULL) {
  - i = -EAFNOSUPPORT;
  - goto out;
- }

/*
 *	Allocate the socket and allow the family to set things up. if
 *	the protocol is 0, the family is instructed to select an appropriate
 *	default. */
- if (!(sock = sock_alloc())) 
- {
  - printk(KERN_WARNING "socket: no more sockets\n");
  - i = -ENFILE;	/* Not exactly a match, but its the closest posix thing */
  - goto out;
- }
- sock->type  = type;
- if ((i = net_families[family]->create(sock, protocol)) < 0)			: inet6_create()
- {
  - sock_release(sock);
  - goto out;
- }
- *res = sock;

out:
- net_family_read_unlock();
- return i;
}

struct net_proto_family inet6_family_ops = {
	PF_INET6,
	inet6_create
};

static struct inet_protosw tcpv6_protosw = {
	type:        SOCK_STREAM,
	protocol:    IPPROTO_TCP,
	prot:        &tcpv6_prot,
	ops:         &inet6_stream_ops,
	capability:  -1,
	no_check:    0,
	flags:       INET_PROTOSW_PERMANENT,
};

struct proto tcpv6_prot = {						: struct sock -> prot
	name:		"TCPv6",
	close:		tcp_close,
	connect:	tcp_v6_connect,
	disconnect:	tcp_disconnect,
	accept:		tcp_accept,
	ioctl:		tcp_ioctl,
	init:		tcp_v6_init_sock,
	destroy:	tcp_v6_destroy_sock,
	shutdown:	tcp_shutdown,
	setsockopt:	tcp_setsockopt,
	getsockopt:	tcp_getsockopt,
	sendmsg:	tcp_sendmsg,
	recvmsg:	tcp_recvmsg,
	backlog_rcv:	tcp_v6_do_rcv,
	hash:		tcp_v6_hash,
	unhash:		tcp_unhash,
	get_port:	tcp_v6_get_port,
};

struct proto_ops inet6_stream_ops = {					: struct socket -> ops
	family:		PF_INET6,

	release:	inet6_release,
	bind:		inet6_bind,
	connect:	inet_stream_connect,		/* ok		*/
	socketpair:	sock_no_socketpair,		/* a do nothing	*/
	accept:		inet_accept,			/* ok		*/
	getname:	inet6_getname, 
	poll:		tcp_poll,			/* ok		*/
	ioctl:		inet6_ioctl,			/* must change  */
	listen:		inet_listen,			/* ok		*/
	shutdown:	inet_shutdown,			/* ok		*/
	setsockopt:	inet_setsockopt,		/* ok		*/
	getsockopt:	inet_getsockopt,		/* ok		*/
	sendmsg:	inet_sendmsg,			/* ok		*/
	recvmsg:	inet_recvmsg,			/* ok		*/
	mmap:		sock_no_mmap,
	sendpage:	tcp_sendpage
};

static int inet6_create(struct socket *sock, int protocol)		: sock->type = SOCK_STREAM, protocol = IPPROTO_TCP
{
	struct sock *sk;
	struct list_head *p;
	struct inet_protosw *answer;
- sk = sk_alloc(PF_INET6, GFP_KERNEL, 1);
- if (sk == NULL) goto do_oom;
	/* Look for the requested type/protocol pair. */
- answer = NULL;
- br_read_lock_bh(BR_NETPROTO_LOCK);
- list_for_each(p, &inetsw6[sock->type]) {				: #define list_for_each(pos, head) =
									: for (pos = (head)->next, prefetch(pos->next); pos != (head); \
									: 	pos = pos->next, prefetch(pos->next))
									: prefetch(x) = x  CPU cache ˤ(⤷ʤ)
  - answer = list_entry(p, struct inet_protosw, list);			: #define list_entry(pty, type, member) =
									: ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
									: list_add(&p->list,&inetsw6[p->type] ϿƤ뤫
		/* Check the non-wild match. */
  - if (protocol == answer->protocol) {
    - if (protocol != IPPROTO_IP) break;
  - } else {
			/* Check for the two wild cases. */
    - if (IPPROTO_IP == protocol) {
      - protocol = answer->protocol;
      - break;
    - }
    - if (IPPROTO_IP == answer->protocol) break;
  - }
  - answer = NULL;
- }
- br_read_unlock_bh(BR_NETPROTO_LOCK);

- if (!answer) goto free_and_badtype;
- if (answer->capability > 0 && !capable(answer->capability)) goto free_and_badperm;
- if (!protocol) goto free_and_noproto;

- sock->ops = answer->ops;
- sock_init_data(sock, sk);						: sk νsock ȤδϢդ
- sk->prot = answer->prot;
- sk->no_check = answer->no_check;
- if (INET_PROTOSW_REUSE & answer->flags) sk->reuse = 1;
- if (SOCK_RAW == sock->type) {
  - sk->num = protocol;
  - if (IPPROTO_RAW == protocol) sk->protinfo.af_inet.hdrincl = 1;
- }

- sk->destruct            = inet6_sock_destruct;
- sk->zapped		= 0;
- sk->family		= PF_INET6;
- sk->protocol		= protocol;
- sk->backlog_rcv		= answer->prot->backlog_rcv;
- sk->net_pinfo.af_inet6.hop_limit  = -1;
- sk->net_pinfo.af_inet6.mcast_hops = -1;
- sk->net_pinfo.af_inet6.mc_loop	  = 1;
- sk->net_pinfo.af_inet6.pmtudisc	  = IPV6_PMTUDISC_WANT;
- sk->net_pinfo.af_inet6.ipv6only   = ipv6_devconf.bindv6only;
	/* Init the ipv4 part of the socket since we can have sockets
	 * using v6 API for ipv4.
	 */
- sk->protinfo.af_inet.ttl	= 64;
- sk->protinfo.af_inet.mc_loop	= 1;
- sk->protinfo.af_inet.mc_ttl	= 1;
- sk->protinfo.af_inet.mc_index	= 0;
- sk->protinfo.af_inet.mc_list	= NULL;

- if (ipv4_config.no_pmtu_disc)
  - sk->protinfo.af_inet.pmtudisc = IP_PMTUDISC_DONT;
- else
  - sk->protinfo.af_inet.pmtudisc = IP_PMTUDISC_WANT;

#ifdef INET_REFCNT_DEBUG
- atomic_inc(&inet6_sock_nr);
- atomic_inc(&inet_sock_nr);
#endif
- MOD_INC_USE_COUNT;

- if (sk->num) {							: SOCK_RAW λ sk->num ˤ protocol 
		/* It assumes that any protocol which allows
		 * the user to assign a number at socket
		 * creation time automatically shares.
		 */
  - sk->sport = ntohs(sk->num);
  - sk->prot->hash(sk);
- }
- if (sk->prot->init) {							: tcp_v6_init_sock()
  - int err = sk->prot->init(sk);					: sk->tp_pinfo.af_tcp ν
  - if (err != 0) {
    - MOD_DEC_USE_COUNT;
    - inet_sock_release(sk);
    - return err;
  - }
- }
- return 0;

free_and_badtype:
- sk_free(sk);
- return -ESOCKTNOSUPPORT;
free_and_badperm:
- sk_free(sk);
- return -EPERM;
free_and_noproto:
- sk_free(sk);
- return -EPROTONOSUPPORT;
do_oom:
- return -ENOBUFS;
}

static int tcp_v6_init_sock(struct sock *sk)
{
	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
- skb_queue_head_init(&tp->out_of_order_queue);
- tcp_init_xmit_timers(sk);
- tcp_prequeue_init(tp);
- tp->rto  = TCP_TIMEOUT_INIT;
- tp->mdev = TCP_TIMEOUT_INIT;
	/* So many TCP implementations out there (incorrectly) count the
	 * initial SYN frame in their delayed-ACK and congestion control
	 * algorithms that we must have the following bandaid to talk
	 * efficiently to them.  -DaveM
	 */
- tp->snd_cwnd = 2;
	/* See draft-stevens-tcpca-spec-01 for discussion of the
	 * initialization of these values.
	 */
- tp->snd_ssthresh = 0x7fffffff;
- tp->snd_cwnd_clamp = ~0;
- tp->mss_cache = 536;
- tp->reordering = sysctl_tcp_reordering;
- sk->state = TCP_CLOSE;
- sk->tp_pinfo.af_tcp.af_specific = &ipv6_specific;
- sk->write_space = tcp_write_space;
- sk->use_write_queue = 1;
- sk->sndbuf = sysctl_tcp_wmem[1];
- sk->rcvbuf = sysctl_tcp_rmem[1];
- atomic_inc(&tcp_sockets_allocated);
- return 0;
}

static struct tcp_func ipv6_specific = {					: sk->tp_pinfo.af_tcp.af_specific
	tcp_v6_xmit,
	tcp_v6_send_check,
	tcp_v6_rebuild_header,
	tcp_v6_conn_request,
	tcp_v6_syn_recv_sock,
	tcp_v6_remember_stamp,
	sizeof(struct ipv6hdr),

	ipv6_setsockopt,
	ipv6_getsockopt,
	v6_addr2sockaddr,
	sizeof(struct sockaddr_in6)
};

asmlinkage long sys_bind(int fd, struct sockaddr *umyaddr, int addrlen)
{
	struct socket *sock;
	char address[MAX_SOCK_ADDR];
	int err;
- if((sock = sockfd_lookup(fd,&err))!=NULL)
- {
  - if((err=move_addr_to_kernel(umyaddr,addrlen,address))>=0)			: copy a socket address into kernel space
    - err = sock->ops->bind(sock, (struct sockaddr *)address, addrlen);		: inet6_bind()
  - sockfd_put(sock);
- }
- return err;
}

static int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
{
	struct sockaddr_in6 *addr=(struct sockaddr_in6 *)uaddr;
	struct sock *sk = sock->sk;
	__u32 v4addr = 0;
	unsigned short snum;
	int addr_type = 0;
/* If the socket has its own bind function then use it. */
- if(sk->prot->bind) return sk->prot->bind(sk, uaddr, addr_len);		: tcpv6_prot ˤ bind() ̵
- if (addr_len < SIN6_LEN_RFC2133) return -EINVAL;
- addr_type = ipv6_addr_type(&addr->sin6_addr);
- if ((addr_type & IPV6_ADDR_MULTICAST) && sock->type == SOCK_STREAM) return -EINVAL;	: Multicast  TCP ̵

	/* Check if the address belongs to the host. */
- if (addr_type == IPV6_ADDR_MAPPED) {
  - v4addr = addr->sin6_addr.s6_addr32[3];
  - if (inet_addr_type(v4addr) != RTN_LOCAL) return -EADDRNOTAVAIL;
- } else {
  - if (addr_type != IPV6_ADDR_ANY) {
			/* ipv4 addr of the socket is invalid.  Only the
			 * unpecified and mapped address have a v4 equivalent.	: typo = unpecified -> unspecified
			 */
    - v4addr = LOOPBACK4_IPV6;
    - if (!(addr_type & IPV6_ADDR_MULTICAST))	{
      - if (!ipv6_chk_addr(&addr->sin6_addr, NULL)) return -EADDRNOTAVAIL;
    - }
  - }
- }
- snum = ntohs(addr->sin6_port);
- if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) return -EACCES;
- lock_sock(sk);
	/* Check these errors (active socket, double bind). */
- if ((sk->state != TCP_CLOSE) || (sk->num != 0)) {
  - release_sock(sk);
  - return -EINVAL;
- }
- if (addr_type & IPV6_ADDR_LINKLOCAL) {
  - if (addr_len >= sizeof(struct sockaddr_in6) && addr->sin6_scope_id) {
			/* Override any existing binding, if another one
			 * is supplied by user.
			 */
    - sk->bound_dev_if = addr->sin6_scope_id;
  - }
#ifndef CONFIG_IPV6_LOOSE_SCOPE_ID
		/* Binding to link-local address requires an interface */
  - if (sk->bound_dev_if == 0) {
    - release_sock(sk);
    - return -EINVAL;
  - }
#endif
- }
- else if ((addr_type == IPV6_ADDR_MAPPED) && sk->net_pinfo.af_inet6.ipv6only) {	: ipv6only  v4 
  - release_sock(sk);
  - return -EINVAL;
- }
- sk->rcv_saddr = v4addr;
- sk->saddr = v4addr;
- ipv6_addr_copy(&sk->net_pinfo.af_inet6.rcv_saddr, &addr->sin6_addr);		: sin6_addr  rcv_saddr  in6_addr ʬԡ
- if (!(addr_type & IPV6_ADDR_MULTICAST)) ipv6_addr_copy(&sk->net_pinfo.af_inet6.saddr, &addr->sin6_addr);
	/* Make sure we are allowed to bind here. */
- if (sk->prot->get_port(sk, snum) != 0) {					: tcp_v6_get_port()
  - sk->rcv_saddr = 0;
  - sk->saddr = 0;
  - memset(&sk->net_pinfo.af_inet6.rcv_saddr, 0, sizeof(struct in6_addr));
  - memset(&sk->net_pinfo.af_inet6.saddr, 0, sizeof(struct in6_addr));
  - release_sock(sk);
  - return -EADDRINUSE;
- }
- if (addr_type != IPV6_ADDR_ANY) sk->userlocks |= SOCK_BINDADDR_LOCK;
- if (snum) sk->userlocks |= SOCK_BINDPORT_LOCK;
- sk->sport = ntohs(sk->num);
- sk->dport = 0;
- sk->daddr = 0;
- release_sock(sk);
- return 0;
}

int ipv6_addr_type(struct in6_addr *addr)				: ɥ쥹η֤
{
	ff00::/8	= IPV6_ADDR_MULTICAST
	ff01::/16	= IPV6_ADDR_MULTICAST | IPV6_ADDR_LOOPBACK
	ff02::/16	= IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL
	ff05::/16	= IPV6_ADDR_MULTICAST | IPV6_ADDR_SITELOCAL
	::/128		= IPV6_ADDR_ANY
	::1/128		= IPV6_ADDR_LOOPBACK
	::/96		= IPV6_ADDR_COMPATv4
	::ffff/96	= IPV6_ADDR_MAPPED
	::/3		= IPV6_ADDR_RESERVED
	fe80::/10	= IPV6_ADDR_LINKLOCAL
	fec0::/10	= IPV6_ADDR_SITELOCAL
	other		= IPV6_ADDR_ANYCAST, IPV6_ADDR_UNICAST
}

static int tcp_v6_get_port(struct sock *sk, unsigned short snum)
{
	struct tcp_bind_hashbucket *head;
	struct tcp_bind_bucket *tb;
#if defined(CONFIG_NET_RESTRICTED_REUSE) || defined(CONFIG_IPV6_RESTRICTED_DOUBLE_BIND)
	uid_t sk_uid = sk->state != TCP_TIME_WAIT ? sock_i_uid_t(sk) : ((struct tcp_tw_bucket *)sk)->uid;
#endif
	int ret;
- local_bh_disable();
- if (snum == 0) {
	int low = sysctl_local_port_range[0];
	int high = sysctl_local_port_range[1];
	int remaining = (high - low) + 1;
	int rover;
  - spin_lock(&tcp_portalloc_lock);
  - rover = tcp_port_rover;
  - do {	rover++;
    - if ((rover < low) || (rover > high)) rover = low;
    - head = &tcp_bhash[tcp_bhashfn(rover)];
    - spin_lock(&head->lock);
    - for (tb = head->chain; tb; tb = tb->next)
      - if (tb->port == rover) goto next;
    - break;
next:
    - spin_unlock(&head->lock);
  - } while (--remaining > 0);
  - tcp_port_rover = rover;
  - spin_unlock(&tcp_portalloc_lock);
		/* Exhausted local port range during search? */
  - ret = 1;
  - if (remaining <= 0) goto fail;
		/* OK, here is the one we will use. */
  - snum = rover;
  - tb = NULL;
- } else {
  - head = &tcp_bhash[tcp_bhashfn(snum)];
  - spin_lock(&head->lock);
  - for (tb = head->chain; tb != NULL; tb = tb->next)
    - if (tb->port == snum) break;
- }
- if (tb != NULL && tb->owners != NULL) {
  - if (tb->fastreuse > 0 && (sk->reuse != 0
#ifdef SO_REUSEPORT
		     || sk->reuseport != 0
#endif
		    ) &&
#if defined(CONFIG_NET_RESTRICTED_REUSE)
		    sk_uid == tb->uid &&
#endif
		    sk->state != TCP_LISTEN) {
    - goto success;
  - } else {
	struct sock *sk2 = tb->owners;
	int sk_reuse, sk2_reuse;
	struct in6_addr *sk_rcv_saddr6 = sk->state != TCP_TIME_WAIT ? 
						&sk->net_pinfo.af_inet6.rcv_saddr:
						&((struct tcp_tw_bucket*)sk)->v6_rcv_saddr;
	int addr_type = ipv6_addr_type(sk_rcv_saddr6), addr_type2;
#if defined(CONFIG_NET_RESTRICTED_REUSE) || defined(CONFIG_IPV6_RESTRICTED_DOUBLE_BIND)
	uid_t sk2_uid;
#endif
    - sk_reuse = 0;
    - if (sk->reuse) sk_reuse |= 1;
#ifdef SO_REUSEPORT
    - if (sk->reuseport) sk_reuse |= 2;
#endif
#if 0
    - if (sk_reuse && (addr_type != IPV6_ADDR_MAPPED ? (addr_type & IPV6_ADDR_MULTICAST) : MULTICAST(sk->rcv_saddr)))
      - sk_reuse |= 4;
#endif
			/* We must walk the whole port owner list in this case. -DaveM */
    - for( ; sk2 != NULL; sk2 = sk2->bind_next) {
#if defined(CONFIG_NET_RESTRICTED_REUSE) || defined(CONFIG_IPV6_RESTRICTED_DOUBLE_BIND)
	int uid_ok;
#endif
	int both_specified = 0;
	struct in6_addr *sk2_rcv_saddr6;
      - if (sk2 == sk || (sk2->bound_dev_if && sk->bound_dev_if && sk2->bound_dev_if != sk->bound_dev_if))
        - continue;
#if 0
      - if (sk2->family != AF_INET6 && sk2->family != AF_INET) continue;
#endif
      - sk2_rcv_saddr6 = sk2->state != TCP_TIME_WAIT ? &sk2->net_pinfo.af_inet6.rcv_saddr : &((struct tcp_tw_bucket*)sk2)->v6_rcv_saddr;
      - addr_type2 = sk2->family == AF_INET6 ? ipv6_addr_type(sk2_rcv_saddr6) : IPV6_ADDR_MAPPED;
#if defined(CONFIG_NET_RESTRICTED_REUSE) || defined(CONFIG_IPV6_RESTRICTED_DOUBLE_BIND)
      - sk2_uid = sk2->state != TCP_TIME_WAIT ? sock_i_uid_t(sk2) : ((struct tcp_tw_bucket *)sk2)->uid;
#endif
      - if ((addr_type2 != IPV6_ADDR_MAPPED ? addr_type2 != IPV6_ADDR_ANY : sk2->rcv_saddr) &&
		(addr_type != IPV6_ADDR_MAPPED ? addr_type != IPV6_ADDR_ANY : sk->rcv_saddr)) {
        - if (addr_type2 == IPV6_ADDR_MAPPED || addr_type == IPV6_ADDR_MAPPED) {
          - if (addr_type2 != addr_type || sk2->rcv_saddr != sk->rcv_saddr) continue;
        - } else {
          - if (ipv6_addr_cmp(sk2_rcv_saddr6, sk_rcv_saddr6)) continue;
        - }
        - both_specified = 1;
      - }
#if defined(CONFIG_NET_RESTRICTED_REUSE) || defined(CONFIG_IPV6_RESTRICTED_DOUBLE_BIND)
      - uid_ok = sk2_uid == (uid_t) -1 || sk_uid == sk2_uid;
#endif
      - if ((addr_type2 == IPV6_ADDR_MAPPED && addr_type != IPV6_ADDR_MAPPED && sk->net_pinfo.af_inet6.ipv6only) ||
		(addr_type == IPV6_ADDR_MAPPED && addr_type2 != IPV6_ADDR_MAPPED && sk2->net_pinfo.af_inet6.ipv6only)) {
#ifdef CONFIG_IPV6_RESTRICTED_DOUBLE_BIND
        - if (ipv6_devconf.bindv6only_restriction == 0 || uid_ok) continue;
#else
        - continue;
#endif
      - }
      - sk2_reuse = 0;
      - if (sk2->reuse) sk2_reuse |= 1;
#ifdef SO_REUSEPORT
      - if (sk2->reuseport) sk2_reuse |= 2;
#endif
#if 0
      - if (sk2_reuse && (addr_type2 != IPV6_ADDR_MAPPED ? (addr_type2 & IPV6_ADDR_MULTICAST) : MULTICAST(sk2->rcv_saddr)))
        - sk2_reuse |= 4;
#endif
      - if (sk2_reuse & sk_reuse & 3) {	/* NOT && */
        - ret = 1;
#if 0
        - if (sk2_reuse & sk_reuse & 4) continue;
#endif
#ifdef CONFIG_NET_RESTRICTED_REUSE
        - if (!uid_ok) goto fail_unlock;
#endif
#ifdef SO_REUSEPORT
        - if (sk2_reuse & sk_reuse & 2) continue;
#endif
        - if (both_specified) {
		struct in6_addr *sk2_daddr6 = sk2->state != TCP_TIME_WAIT ?
						&sk2->net_pinfo.af_inet6.daddr :
						&((struct tcp_tw_bucket*)sk2)->v6_daddr;
		int addr_type2d = sk2->family == AF_INET6 ? ipv6_addr_type(sk2_daddr6) : IPV6_ADDR_MAPPED;
          - if (addr_type2d != IPV6_ADDR_MAPPED ? addr_type2d != IPV6_ADDR_ANY : sk2->daddr) continue;
        - } else {
          - if ((addr_type2 != IPV6_ADDR_MAPPED ? addr_type2 != IPV6_ADDR_ANY : sk2->rcv_saddr) || 
			(addr_type != IPV6_ADDR_MAPPED ? addr_type != IPV6_ADDR_ANY : sk->rcv_saddr)) continue;
        - }
      - }
      - ret = 1;
      - goto fail_unlock;
    - }
			/* If we found a conflict, fail. */
    - ret = 1;
    - if (sk2 != NULL) goto fail_unlock;
  - }
- }
- ret = 1;
- if (tb == NULL && (tb = tcp_bucket_create(head, snum)) == NULL) goto fail_unlock;
- if (tb->owners == NULL) {
  - if ((sk->reuse 
#ifdef SO_REUSEPORT
		     || sk->reuseport
#endif
		    ) && sk->state != TCP_LISTEN) {
    - tb->fastreuse = 1;
#if defined(CONFIG_NET_RESTRICTED_REUSE)
    - tb->uid = sk_uid;
#endif
  - } else tb->fastreuse = 0;
- } else if (tb->fastreuse && ((sk->reuse == 0
#ifdef SO_REUSEPORT
		     && sk_reuseport == 0
#endif
		     ) ||
#if defined(CONFIG_NET_RESTRICTED_REUSE)
		    (sk_uid != tb->uid) ||
#endif
		    (sk->state == TCP_LISTEN)))
  - tb->fastreuse = 0;
success:
- sk->num = snum;
- if (sk->prev == NULL) {
  - if ((sk->bind_next = tb->owners) != NULL) tb->owners->bind_pprev = &sk->bind_next;
  - tb->owners = sk;
  - sk->bind_pprev = &tb->owners;
  - sk->prev = (struct sock *) tb;
- } else {
  - BUG_TRAP(sk->prev == (struct sock *) tb);
- }
- ret = 0;
fail_unlock:
- spin_unlock(&head->lock);
fail:
- local_bh_enable();
- return ret;
}

asmlinkage long sys_listen(int fd, int backlog)
{
	struct socket *sock;
	int err;
- if ((sock = sockfd_lookup(fd, &err)) != NULL) {
  - if ((unsigned) backlog > SOMAXCONN) backlog = SOMAXCONN;
  - err=sock->ops->listen(sock, backlog);				: inet_listen
  - sockfd_put(sock);
- }
- return err;
}

int inet_listen(struct socket *sock, int backlog)
{
	struct sock *sk = sock->sk;
	unsigned char old_state;
	int err;
- lock_sock(sk);
- err = -EINVAL;
- if (sock->state != SS_UNCONNECTED || sock->type != SOCK_STREAM) goto out;
- old_state = sk->state;
- if (!((1<<old_state)&(TCPF_CLOSE|TCPF_LISTEN))) goto out;
	/* Really, if the socket is already in listen state
	 * we can only allow the backlog to be adjusted.
	 */
- if (old_state != TCP_LISTEN) {
  - err = tcp_listen_start(sk);
  - if (err) goto out;
- }
- sk->max_ack_backlog = backlog;
- err = 0;
out:
- release_sock(sk);
- return err;
}

int tcp_listen_start(struct sock *sk)
{
	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
	struct tcp_listen_opt *lopt;
- sk->max_ack_backlog = 0;
- sk->ack_backlog = 0;
- tp->accept_queue = tp->accept_queue_tail = NULL;
- tp->syn_wait_lock = RW_LOCK_UNLOCKED;
- tcp_delack_init(tp);							: tp->ack  0 ǽ롣
- lopt = kmalloc(sizeof(struct tcp_listen_opt), GFP_KERNEL);
- if (!lopt) return -ENOMEM;
- memset(lopt, 0, sizeof(struct tcp_listen_opt));
- for (lopt->max_qlen_log = 6; ; lopt->max_qlen_log++)
  - if ((1<<lopt->max_qlen_log) >= sysctl_max_syn_backlog) break;
- write_lock_bh(&tp->syn_wait_lock);
- tp->listen_opt = lopt;
- write_unlock_bh(&tp->syn_wait_lock);
	/* There is race window here: we announce ourselves listening,
	 * but this transition is still not validated by get_port().
	 * It is OK, because this socket enters to hash table only
	 * after validation is complete.
	 */
- sk->state = TCP_LISTEN;
- if (sk->prot->get_port(sk, sk->num) == 0) {
  - sk->sport = htons(sk->num);
  - sk_dst_reset(sk);							: ?
  - sk->prot->hash(sk);
  - return 0;
- }
- sk->state = TCP_CLOSE;
- write_lock_bh(&tp->syn_wait_lock);
- tp->listen_opt = NULL;
- write_unlock_bh(&tp->syn_wait_lock);
- kfree(lopt);
- return -EADDRINUSE;
}



asmlinkage long sys_accept(int fd, struct sockaddr *upeer_sockaddr, int *upeer_addrlen)
{
	struct socket *sock, *newsock;
	int err, len;
	char address[MAX_SOCK_ADDR];
- sock = sockfd_lookup(fd, &err);
- if (!sock) goto out;
- err = -EMFILE;
- if (!(newsock = sock_alloc())) goto out_put;
- newsock->type = sock->type;
- newsock->ops = sock->ops;						: socket->ops  struct proto_ops
- err = sock->ops->accept(sock, newsock, sock->file->f_flags);		:  accept  inet_accept
- if (err < 0) goto out_release;
- if (upeer_sockaddr) {
  - if(newsock->ops->getname(newsock, (struct sockaddr *)address, &len, 2)<0) {
    - err = -ECONNABORTED;
    - goto out_release;
  - }
  - err = move_addr_to_user(address, len, upeer_sockaddr, upeer_addrlen);	: ?
  - if (err < 0) goto out_release;
- }
	/* File flags are not inherited via accept() unlike another OSes. */
- if ((err = sock_map_fd(newsock)) < 0) goto out_release;

out_put:
- sockfd_put(sock);
out:
- return err;
out_release:
- sock_release(newsock);
- goto out_put;
}

int inet_accept(struct socket *sock, struct socket *newsock, int flags)
{
	struct sock *sk1 = sock->sk;
	struct sock *sk2;
	int err = -EINVAL;
- if((sk2 = sk1->prot->accept(sk1,flags,&err)) == NULL) goto do_err;	:  accept  tcp_accept
- lock_sock(sk2);
- BUG_TRAP((1<<sk2->state)&(TCPF_ESTABLISHED|TCPF_CLOSE_WAIT|TCPF_CLOSE));
- sock_graft(sk2, newsock);						: sk2  newsock ϢŤ
- newsock->state = SS_CONNECTED;
- release_sock(sk2);
- return 0;

do_err:
- return err;
}

struct sock *tcp_accept(struct sock *sk, int flags, int *err)
{
	struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
	struct open_request *req;
	struct sock *newsk;
	int error;
- lock_sock(sk); 
	/* We need to make sure that this socket is listening,
	 * and that it has something pending.
	 */
- error = -EINVAL;
- if (sk->state != TCP_LISTEN) goto out;
	/* Find already established connection */
- if (!tp->accept_queue) {
  - long timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);			: ?
		/* If this is a non blocking socket don't sleep */
  - error = -EAGAIN;
  - if (!timeo) goto out;
  - error = wait_for_connect(sk, timeo);				: ?
  - if (error) goto out;
- }
- req = tp->accept_queue;
- if ((tp->accept_queue = req->dl_next) == NULL) tp->accept_queue_tail = NULL;
- newsk = req->sk;							: 줬 accept 줿å = tp->accept_queue->sk
- tcp_acceptq_removed(sk);						: ?
- tcp_openreq_fastfree(req);						: ?
- BUG_TRAP(newsk->state != TCP_SYN_RECV);
- release_sock(sk);
- return newsk;
out:
- release_sock(sk);
- *err = error; 
- return NULL;
}

static inline void sock_graft(struct sock *sk, struct socket *parent)
{
- write_lock_bh(&sk->callback_lock);
- sk->sleep = &parent->wait;
- parent->sk = sk;
- sk->socket = parent;
- write_unlock_bh(&sk->callback_lock);
}

狼äȡ
rawv6_sendmsg  udpv6_connect  udpv6_sendmsg ˤ np->sndflow åȤ뤬
tcp ˤ tcp_v6_connect ˤåƤȤ̵
tcpv6_prot  sendmsg  tcp_sendmsg
