static char rcsident
[] = "$Header: in_pcb.c,v 1.12 84/11/29 17:02:13 walsh Exp $";
#include "../h/socketvar.h"
#include "../h/protosw.h"
#include "../net/route.h"
#include "../bbnnet/in.h"
#include "../bbnnet/net.h"
#include "../bbnnet/in_pcb.h"
#include "../bbnnet/in_var.h"
extern struct rtentry
*ip_route();
extern struct domain inetdomain
;
register struct inpcb
*inp
;
m
= m_getclr(M_DONTWAIT
, MT_PCB
);
inp
= mtod(m
, struct inpcb
*);
so
->so_pcb
= (caddr_t
)inp
;
* changed from 4.2 to accept a structure which has protocol
* specific data like how to break down port allocation.
in_pcbbind(inp
, nam
, advice
)
register struct inpcb
*inp
;
struct pr_advice
*advice
;
register struct socket
*so
= inp
->inp_socket
;
register struct sockaddr_in
*sin
;
register u_short lport
= 0;
* socket must not already be bound
if (inp
->inp_lport
|| inp
->inp_laddr
.s_addr
!= INADDR_ANY
)
sin
= mtod(nam
, struct sockaddr_in
*);
if (nam
->m_len
!= sizeof (*sin
))
* Since Berkeley left this out, some of their programs (ftpd)
if (sin->sin_family != AF_INET)
if (sin
->sin_addr
.s_addr
!= INADDR_ANY
)
/* some code says ..withnet() */
if (in_iawithaddr(sin
->sin_addr
, FALSE
) == NULL
)
/* user gives port to us in net order */
if (lport
= sin
->sin_port
)
/* if portsize > 2 a major rewrite needed to
if (advice
->portsize
> 1)
aport
= lport
; /* a char is a char */
* really only a worry for byte size ports
if (aport
> advice
->maxport
)
if (aport
<= advice
->rootport
&& u
.u_uid
!= 0)
* Check to see if the local address/port is in use.
* but, process may use this pair to communicate with
* several destinations (each with its own tcp) if he
(*(advice
->bind_used
))(inp
, /* current binding */
lport
, /* desired port */
sin
->sin_addr
.s_addr
, /* desired address */
so
->so_options
& SO_REUSEADDR
))
inp
->inp_laddr
= sin
->sin_addr
;
/* any ports for random allocation by non-root users? */
if ((advice
->maxport
<= advice
->resvport
) && (u
.u_uid
))
* Allow for reserved ports for non-super users
* so that don't interfere with some project's software.
u_short possible
= advice
->nowport
;
if (advice
->portsize
> 1)
if (possible
>= advice
->maxport
)
possible
= advice
->resvport
+ 1;
* no free ports??? RDP/HMP problem
if (possible
== advice
->nowport
)
while (advice
->bind_used
&&
(*(advice
->bind_used
))(inp
, lport
, inp
->inp_laddr
.s_addr
, 0));
advice
->nowport
= possible
;
* Connect from a socket to a specified address.
* Both address and port must be specified in argument sin.
* If don't have a local address for this socket yet,
in_pcbconnect(inp
, nam
, conn_used
)
register struct ifnet
*ifp
= NULL
;
register struct in_ifaddr
*ia
= NULL
;
register struct sockaddr_in
*ifaddr
;
register struct sockaddr_in
*sin
= mtod(nam
, struct sockaddr_in
*);
register struct rtentry
*rt
;
struct sockaddr_in
*inpsin
;
if (nam
->m_len
!= sizeof (*sin
))
if (sin
->sin_family
!= AF_INET
)
if (sin
->sin_addr
.s_addr
== INADDR_ANY
|| sin
->sin_port
== 0)
* Find route for connection. For a tcp connecting to a server,
* this route will be used for the duration of the connection
* (unless redirected...). For a UDP doing a connect, this route
* will also be used for the duration. For a UDP unconnected send,
* this route will be used for the current packet.
* rtalloc cannot handle routing with both sides already bound
rt
= (struct rtentry
*) NULL
;
* NOTE: programmers often forget to zero sin_zero[0-1].
* rtalloc does not want to know the port number for routes to hosts.
inpsin
= (struct sockaddr_in
*) &inp
->inp_route
.ro_dst
;
bcopy((caddr_t
)sin
, (caddr_t
)inpsin
, sizeof (*sin
));
if (inp
->inp_laddr
.s_addr
== INADDR_ANY
)
rtalloc(&inp
->inp_route
);
if (rt
= inp
->inp_route
.ro_rt
)
if (rt
= ip_route(&inp
->inp_laddr
, &sin
->sin_addr
))
inp
->inp_route
.ro_rt
= rt
;
* find Internet address structure for this interface.
ifaddr
= (struct sockaddr_in
*) &ia
->ia_addr
;
* 8.7.0.2 (on IMP net) can send to 128.11.0.0 (on Ethernet), but
if (in_broadcast(sin
->sin_addr
) &&
iptonet(sin
->sin_addr
) == iptonet(ifaddr
->sin_addr
) &&
!(ifp
->if_flags
& IFF_BROADCAST
) )
inp
->inp_route
.ro_rt
= NULL
;
(inp
->inp_laddr
.s_addr
? inp
->inp_laddr
.s_addr
: ifaddr
->sin_addr
.s_addr
),
sin
->sin_addr
.s_addr
) != (char *)NULL
)
inp
->inp_route
.ro_rt
= NULL
;
if (inp
->inp_laddr
.s_addr
== INADDR_ANY
)
inp
->inp_laddr
= ifaddr
->sin_addr
;
inp
->inp_faddr
= sin
->sin_addr
;
inp
->inp_fport
= sin
->sin_port
;
in_pcbdisconnect(inp
, pcb_free_func
)
inp
->inp_faddr
.s_addr
= INADDR_ANY
;
* may attach a route to an inpcb several times. For example,
* when UDP does unconnected, but bound, sends.
if (inp
->inp_route
.ro_rt
)
rtfree(inp
->inp_route
.ro_rt
);
inp
->inp_route
.ro_rt
= NULL
;
if (inp
->inp_socket
->so_state
& SS_NOFDREF
)
in_pcbdetach(inp
, pcb_free_func
);
* Don't need to splnet while altering lists, since called from places
* where that has already been done.
in_pcbdetach(inp
, pcb_free_func
)
register struct inpcb
*inp
;
register struct socket
*so
;
if (so
= inp
->inp_socket
)
so
->so_pcb
= (caddr_t
) NULL
;
/* inp->inp_socket = (struct socket *) NULL; */
if (inp
->inp_route
.ro_rt
)
rtfree(inp
->inp_route
.ro_rt
);
(*pcb_free_func
)(inp
); /* free per-protocol block */
(void) m_free(dtom(inp
));
register struct inpcb
*inp
;
register struct sockaddr_in
*sin
;
nam
->m_len
= sizeof (*sin
);
sin
= mtod(nam
, struct sockaddr_in
*);
bzero((caddr_t
)sin
, sizeof (*sin
));
sin
->sin_family
= AF_INET
;
sin
->sin_port
= inp
->inp_lport
;
sin
->sin_addr
= inp
->inp_laddr
;
register struct inpcb
*inp
;
register struct sockaddr_in
*sin
;
nam
->m_len
= sizeof (*sin
);
sin
= mtod(nam
, struct sockaddr_in
*);
bzero((caddr_t
)sin
, sizeof (*sin
));
sin
->sin_family
= AF_INET
;
sin
->sin_port
= inp
->inp_fport
;
sin
->sin_addr
= inp
->inp_faddr
;
* somewhat different from the one in 4.2 and (I think) substantially
* easier to read, though a bit slower.
* fport == 0 if don't want/need match on remote port # (HMP and UDP)
in_pcblookup(head
,faddr
,fport
,laddr
,lport
,wild
)
register struct inpcb
*inp
;
for(inp
= head
->inp_next
; inp
!= head
; inp
= inp
->inp_next
)
if (inp
->inp_lport
!= lport
)
if (fport
&& (inp
->inp_fport
!= fport
))
if ((inp
->inp_faddr
.s_addr
!= faddr
) || (inp
->inp_laddr
.s_addr
!= laddr
))
for(inp
= head
->inp_next
; inp
!= head
; inp
= inp
->inp_next
)
if (inp
->inp_lport
!= lport
)
if (fport
&& (inp
->inp_fport
!= fport
) && inp
->inp_fport
)
if ((inp
->inp_faddr
.s_addr
) && (inp
->inp_faddr
.s_addr
!= faddr
))
if ((inp
->inp_laddr
.s_addr
) && (inp
->inp_laddr
.s_addr
!= laddr
))
return((struct inpcb
*) NULL
);
* This only advises process and does not internally close socket,
* not so much because the user can do much but close when he gets a
* HOSTDEAD/HOSTUNREACH indication, but because it is possible that
* the destination host has saved connection state information. (His IMP
* interface went down for PM, but the machine stayed up...)
* Also, this makes addition of new protocols easy, since we don't need to
* know the name and calling sequence of their close/abort routine.
* We do not close child sockets of listen(2)ers for connection oriented
* protocols. We let the protocol do that by timing out connection
inpcb_notify(head
, laddr
, faddr
, error
)
register struct inpcb
*head
;
register struct inpcb
*inp
;
for(inp
= head
->inp_next
; inp
!= head
; inp
= inp
->inp_next
)
if (((inp
->inp_faddr
.s_addr
== faddr
) || (faddr
== 0)) &&
((inp
->inp_laddr
.s_addr
== laddr
) || (laddr
== 0)))
advise_user(inp
->inp_socket
, error
);
wakeup((caddr_t
) &so
->so_timeo
); /* in connect(2) */