/* in_pcb.c 4.15 81/12/21 */
#include "../h/socketvar.h"
#include "../net/in_systm.h"
#include "../net/in_pcb.h"
* Routines to manage internet protocol control blocks.
* At PRU_ATTACH time a protocol control block is allocated in
* in_pcballoc() and inserted on a doubly-linked list of such blocks
* for the protocol. A port address is either requested (and verified
* to not be in use) or assigned at this time. We also allocate
* space in the socket sockbuf structures here, although this is
* not a clearly correct place to put this function.
* A connectionless protocol will have its protocol control block
* removed at PRU_DETACH time, when the socket will be freed (freeing
* the space reserved) and the block will be removed from the list of
* blocks for its protocol.
* A connection-based protocol may be connected to a remote peer at
* PRU_CONNECT time through the routine in_pcbconnect(). In the normal
* case a PRU_DISCONNECT occurs causing a in_pcbdisconnect().
* It is also possible that higher-level routines will opt out of the
* relationship with the connection before the connection shut down
* is complete. This often occurs in protocols like TCP where we must
* hold on to the protocol control block for a unreasonably long time
* after the connection is used up to avoid races in later connection
* establishment. To handle this we allow higher-level routines to
* disassociate themselves from the socket, marking it SS_USERGONE while
* the disconnect is in progress. We notice that this has happened
* when the disconnect is complete, and perform the PRU_DETACH operation,
struct in_addr zeroin_addr
;
* Allocate a protocol control block, space
* for send and receive data, and local host information.
* Return error. If no error make socket point at pcb.
in_pcbattach(so
, head
, sndcc
, rcvcc
, sin
)
register struct inpcb
*inp
;
if (sin
->sin_family
!= AF_INET
)
if (ifnet
&& sin
->sin_addr
.s_addr
== 0)
sin
->sin_addr
= ifnet
->if_addr
;
ifp
= if_ifwithaddr(sin
->sin_addr
);
in_pcblookup(head
, zeroin_addr
, 0, sin
->sin_addr
, lport
))
if (sbreserve(&so
->so_snd
, sndcc
) == 0)
if (sbreserve(&so
->so_rcv
, rcvcc
) == 0)
inp
= mtod(m
, struct inpcb
*);
inp
->inp_laddr
= ifp
->if_addr
;
if (head
->inp_lport
++ < 1024)
lport
= htons(head
->inp_lport
);
} while (in_pcblookup(head
, zeroin_addr
, 0, inp
->inp_laddr
, lport
));
so
->so_pcb
= (caddr_t
)inp
;
sin
= (struct sockaddr_in
*)&so
->so_addr
;
sin
->sin_family
= AF_INET
;
sin
->sin_addr
= inp
->inp_laddr
;
sin
->sin_port
= inp
->inp_lport
;
if (sin
->sin_family
!= AF_INET
)
if (sin
->sin_addr
.s_addr
== 0 || sin
->sin_port
== 0)
xp
= in_pcblookup(inp
->inp_head
, sin
->sin_addr
, sin
->sin_port
, inp
->inp_laddr
, inp
->inp_lport
);
if (xp
->inp_faddr
.s_addr
)
inp
->inp_faddr
= sin
->sin_addr
;
inp
->inp_fport
= sin
->sin_port
;
register struct sockaddr_in
*sin
= (struct sockaddr_in
*)sp
;
sin
->sin_family
= AF_INET
;
sin
->sin_port
= inp
->inp_fport
;
sin
->sin_addr
= inp
->inp_faddr
;
inp
->inp_faddr
.s_addr
= 0;
if (inp
->inp_socket
->so_state
& SS_USERGONE
)
struct socket
*so
= inp
->inp_socket
;
(void) m_free(dtom(inp
));
* Look for a control block to accept a segment.
* First choice is an exact address match.
* Second choice is a match of local address, with
* unspecified foreign address.
in_pcblookup(head
, faddr
, fport
, laddr
, lport
)
struct in_addr faddr
, laddr
;
register struct inpcb
*inp
;
for (inp
= head
->inp_next
; inp
!= head
; inp
= inp
->inp_next
) {
if (inp
->inp_laddr
.s_addr
!= laddr
.s_addr
||
if (inp
->inp_faddr
.s_addr
== 0) {
if (inp
->inp_faddr
.s_addr
== faddr
.s_addr
&&