sockfd = socket ( AF_INET, SOCK_STREAM, 0 );The last argument is "protocol" and is provided in case some protocol family (i.e. domain) had multiple protocols. For AF_INET there is only one option, so an argument of 0 will suffice and get the one and only default.
The second argument is "type", which is SOCK_STREAM for a TCP socket, but could be SOCK_DGRAM for UDP.
The system call is handled by sys_socket() in kern/uipc_syscalls.c.
The call creates a "struct filedesc" object which can be indexed by fd by the process making the call. A pointer to the socket is created by these calls:
error = socreate(uap->domain, &so, uap->type, uap->protocol); fp->f_data = (caddr_t)so;So the f_data field holds a pointer to the "struct socket" object.
Our interest now shifts to the routine socreate() in kern/uipc_socket.c
socreate ( AF_INET, &so, SOCK_STREAM, 0 ))This routine is in kern/uipc_socket.c and is fairly short.
It does a lookup to find the protocol (it needs the "struct protosw".
It does a malloc for the "struct socket" and initializes it.
Then it makes this call:
error = (*prp->pr_usrreq)(so, PRU_ATTACH, (struct mbuf *)0, (struct mbuf *)proto, (struct mbuf *)0);Which boils down to (since "proto" is 0):
tcp_usrreq (so, PRU_ATTACH, 0, 0, 0);The function tcp_usrreq() is in tcp_usrreq.c This is a big function, but it is a switch/case on "req", which here is PRU_ATTACH
inp = sotoinpcb(so); error = tcp_attach(so); tp = sototcpcb(so);Here we have:
#define sotoinpcb(so) ((struct inpcb *)(so)->so_pcb) #define sototcpcb(so) (intotcpcb(sotoinpcb(so))) #define intotcpcb(ip) ((struct tcpcb *)(ip)->inp_ppcb)So the real action is in tcp_attach(so), which is also in tcp_usrreq.c
This will make a call (via pointers in protosw) to tcp_usrreq to perform a PRU_ATTACH.
struct inpcb { LIST_ENTRY(inpcb) inp_hash; CIRCLEQ_ENTRY(inpcb) inp_queue; struct inpcbtable *inp_table; int inp_state; /* bind/connect state */ u_int16_t inp_fport; /* foreign port */ u_int16_t inp_lport; /* local port */ struct socket *inp_socket; /* back pointer to socket */ caddr_t inp_ppcb; /* pointer to per-protocol pcb */ struct route inp_route; /* placeholder for routing entry */ int inp_flags; /* generic IP/datagram flags */ struct ip inp_ip; /* header prototype; should have more */ struct mbuf *inp_options; /* IP options */ struct ip_moptions *inp_moptions; /* IP multicast options */ int inp_errormtu; /* MTU of last xmit status = EMSGSIZE */ }; #define inp_faddr inp_ip.ip_dst #define inp_laddr inp_ip.ip_srcThe struct tcpcb is a huge thing and can be found in netinet/tcp_var.h
error = in_pcballoc(so, &tcb); inp = sotoinpcb(so); tp = tcp_newtcpcb(inp);The routine in_pcballoc() is in in_pcb.c -- It does a MALLOC for the "struct inpcb", initializes it, and adds it to the tcb list.
sotoinpcb() is a macro that extracts a single field from a structure (why?).
#define sotoinpcb(so) ((struct inpcb *)(so)->so_pcb)The routine tcp_newtcpcb is in tcp_subr.c -- It does a malloc for a tcpcb, initializes it, then sets a link to it in the inpcb.
Kyu / [email protected]