xref: /csrg-svn/sys/deprecated/bbnnet/in_pcb.c (revision 25559)
125202Skarels #ifdef	RCSIDENT
225202Skarels static char rcsident[] = "$Header: in_pcb.c,v 1.12 84/11/29 17:02:13 walsh Exp $";
325202Skarels #endif	RCSIDENT
425202Skarels 
525202Skarels #include "../h/param.h"
625202Skarels #include "../h/systm.h"
725202Skarels #include "../h/dir.h"
825202Skarels #include "../h/user.h"
925202Skarels #include "../h/mbuf.h"
1025202Skarels #include "../h/socket.h"
1125202Skarels #include "../h/socketvar.h"
1225202Skarels #include "../h/protosw.h"
1325202Skarels #include "../h/domain.h"
1425202Skarels 
1525202Skarels #include "../net/if.h"
1625202Skarels #include "../net/route.h"
1725202Skarels 
1825202Skarels #include "../bbnnet/in.h"
1925202Skarels #include "../bbnnet/net.h"
2025202Skarels #include "../bbnnet/in_pcb.h"
2125202Skarels #include "../bbnnet/in_var.h"
2225202Skarels 
2325202Skarels extern struct rtentry *ip_route();
2425202Skarels extern struct domain  inetdomain;
2525202Skarels 
2625202Skarels in_pcballoc(so, head)
2725202Skarels struct socket *so;
2825202Skarels struct inpcb *head;
2925202Skarels {
3025202Skarels     register struct mbuf *m;
3125202Skarels     register struct inpcb *inp;
3225202Skarels 
3325202Skarels     m = m_getclr(M_DONTWAIT, MT_PCB);
3425202Skarels     if (m == NULL)
3525202Skarels 	return (ENOBUFS);
3625202Skarels 
3725202Skarels     inp = mtod(m, struct inpcb *);
3825202Skarels     inp->inp_socket = so;
3925202Skarels 
4025202Skarels     insque(inp,head);
4125202Skarels 
4225202Skarels     so->so_pcb = (caddr_t)inp;
4325202Skarels 
4425202Skarels     return (0);
4525202Skarels }
4625202Skarels 
4725202Skarels /*
4825202Skarels  * changed from 4.2 to accept a structure which has protocol
4925202Skarels  * specific data like how to break down port allocation.
5025202Skarels  */
5125202Skarels 
in_pcbbind(inp,nam,advice)5225202Skarels in_pcbbind(inp, nam, advice)
5325202Skarels register struct inpcb *inp;
5425202Skarels struct mbuf *nam;
5525202Skarels struct pr_advice *advice;
5625202Skarels {
5725202Skarels     register struct socket *so = inp->inp_socket;
5825202Skarels     register struct sockaddr_in *sin;
5925202Skarels     register u_short lport = 0;
6025202Skarels 
6125202Skarels     if (in_ifaddr == NULL)
6225202Skarels 	return (EADDRNOTAVAIL);
6325202Skarels     /*
6425202Skarels      * socket must not already be bound
6525202Skarels      */
6625202Skarels 
6725202Skarels     if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY)
6825202Skarels 	return (EINVAL);
6925202Skarels 
7025202Skarels     if (nam == 0)
7125202Skarels 	goto noname;
7225202Skarels     sin = mtod(nam, struct sockaddr_in *);
7325202Skarels     if (nam->m_len != sizeof (*sin))
7425202Skarels 	return (EINVAL);
7525202Skarels     /*
7625202Skarels      * Since Berkeley left this out, some of their programs (ftpd)
7725202Skarels      * aren't ready for it
7825202Skarels      *
7925202Skarels     if (sin->sin_family != AF_INET)
8025202Skarels 	    return (EAFNOSUPPORT);
8125202Skarels      */
8225202Skarels 
8325202Skarels     if (sin->sin_addr.s_addr != INADDR_ANY)
8425202Skarels     {
8525202Skarels 	/* some code says ..withnet() */
8625202Skarels 	if (in_iawithaddr(sin->sin_addr, FALSE) == NULL)
8725202Skarels 	    return (EADDRNOTAVAIL);
8825202Skarels 
8925202Skarels     }
9025202Skarels 
9125202Skarels     /* user gives port to us in net order */
9225202Skarels     if (lport = sin->sin_port)
9325202Skarels     {
9425202Skarels 	u_short aport;
9525202Skarels 
9625202Skarels 	/* if portsize > 2 a major rewrite needed to
9725202Skarels 	 * accomodate longs.....
9825202Skarels 	 */
9925202Skarels 
10025202Skarels 	if (advice->portsize > 1)
10125202Skarels 	    aport = ntohs(lport);
10225202Skarels 	else
103*25559Slam 	{
104*25559Slam 	    if (lport != (lport & 0xff))
105*25559Slam 		return(EINVAL);	/* must be 8 bits */
106*25559Slam 
10725202Skarels 	    aport = lport;	/* a char is a char */
108*25559Slam 	}
10925202Skarels 
11025202Skarels 	/*
11125202Skarels 	 *  really only a worry for byte size ports
11225202Skarels 	 */
11325202Skarels 
11425202Skarels 	if (aport > advice->maxport)
11525202Skarels 	    return(EADDRNOTAVAIL);
11625202Skarels 
11725202Skarels 	if (aport <= advice->rootport && u.u_uid != 0)
11825202Skarels 	    return (EACCES);
11925202Skarels 
12025202Skarels 	/*
12125202Skarels 	 * Check to see if the local address/port is in use.
12225202Skarels 	 * but, process may use this pair to communicate with
12325202Skarels 	 * several destinations (each with its own tcp) if he
12425202Skarels 	 * sets SO_REUSEADDR
12525202Skarels 	 */
12625202Skarels 	if (advice->bind_used &&
12725202Skarels 	    (*(advice->bind_used))(inp,		/* current binding */
12825202Skarels 	    lport,			/* desired port */
12925202Skarels 	    sin->sin_addr.s_addr,	/* desired address */
13025202Skarels 	    so->so_options & SO_REUSEADDR))
13125202Skarels 	{
13225202Skarels 	    return (EADDRINUSE);
13325202Skarels 	}
13425202Skarels     }
13525202Skarels     inp->inp_laddr = sin->sin_addr;
13625202Skarels 
13725202Skarels noname :
13825202Skarels     /* any ports for random allocation by non-root users? */
13925202Skarels     if ((advice->maxport <= advice->resvport) && (u.u_uid))
14025202Skarels 	return(EADDRNOTAVAIL);
14125202Skarels 
14225202Skarels     if (lport == 0)
14325202Skarels     {
14425202Skarels 	/*
14525202Skarels 	 * Allow for reserved ports for non-super users
14625202Skarels 	 * so that don't interfere with some project's software.
14725202Skarels 	 */
14825202Skarels 	u_short possible = advice->nowport;
14925202Skarels 
15025202Skarels 	do
15125202Skarels 	{
15225202Skarels 	    if (advice->portsize > 1)
15325202Skarels 		lport = htons(possible);
15425202Skarels 	    else
15525202Skarels 		lport = possible;
15625202Skarels 
15725202Skarels 	    /*
15825202Skarels 	     * catch roll over.....
15925202Skarels 	     */
16025202Skarels 
16125202Skarels 	    if (possible >= advice->maxport)
16225202Skarels 		possible = advice->resvport + 1;
16325202Skarels 	    else
16425202Skarels 		possible++;
16525202Skarels 
16625202Skarels 	    /*
16725202Skarels 	     * no free ports??? RDP/HMP problem
16825202Skarels 	     */
16925202Skarels 
17025202Skarels 	    if (possible == advice->nowport)
17125202Skarels 		return(EADDRNOTAVAIL);
17225202Skarels 
17325202Skarels 	}
17425202Skarels 	while (advice->bind_used &&
17525202Skarels 	    (*(advice->bind_used))(inp, lport, inp->inp_laddr.s_addr, 0));
17625202Skarels 
17725202Skarels 	advice->nowport = possible;
17825202Skarels     }
17925202Skarels     inp->inp_lport = lport;
18025202Skarels     return (0);
18125202Skarels }
18225202Skarels 
18325202Skarels /*
18425202Skarels  * Connect from a socket to a specified address.
18525202Skarels  * Both address and port must be specified in argument sin.
18625202Skarels  * If don't have a local address for this socket yet,
18725202Skarels  * then pick one.
18825202Skarels  */
18925202Skarels in_pcbconnect(inp, nam, conn_used)
19025202Skarels struct inpcb *inp;
19125202Skarels struct mbuf *nam;
19225202Skarels char *(*conn_used)();
19325202Skarels {
19425202Skarels     register struct ifnet *ifp = NULL;
19525202Skarels     register struct in_ifaddr *ia = NULL;
19625202Skarels     register struct sockaddr_in *ifaddr;
19725202Skarels     register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
19825202Skarels     register struct rtentry *rt;
19925202Skarels     struct sockaddr_in *inpsin;
20025202Skarels 
20125202Skarels     if (nam->m_len != sizeof (*sin))
20225202Skarels 	return (EINVAL);
20325202Skarels     if (sin->sin_family != AF_INET)
20425202Skarels 	return (EAFNOSUPPORT);
20525202Skarels     if (sin->sin_addr.s_addr == INADDR_ANY || sin->sin_port == 0)
20625202Skarels 	return (EADDRNOTAVAIL);
20725202Skarels 
20825202Skarels     /*
20925202Skarels      * Find route for connection.  For a tcp connecting to a server,
21025202Skarels      * this route will be used for the duration of the connection
21125202Skarels      * (unless redirected...).  For a UDP doing a connect, this route
21225202Skarels      * will also be used for the duration.  For a UDP unconnected send,
21325202Skarels      * this route will be used for the current packet.
21425202Skarels      *
21525202Skarels      * rtalloc cannot handle routing with both sides already bound
21625202Skarels      */
21725202Skarels     rt = (struct rtentry *) NULL;
21825202Skarels 
21925202Skarels     /*
22025202Skarels      * NOTE: programmers often forget to zero sin_zero[0-1].
22125202Skarels      * rtalloc does not want to know the port number for routes to hosts.
22225202Skarels      */
22325202Skarels     inpsin = (struct sockaddr_in *) &inp->inp_route.ro_dst;
22425202Skarels     bcopy((caddr_t)sin, (caddr_t)inpsin, sizeof (*sin));
22525202Skarels     inpsin->sin_port = 0;
22625202Skarels 
22725202Skarels     if (inp->inp_laddr.s_addr == INADDR_ANY)
22825202Skarels     {
22925202Skarels 	rtalloc(&inp->inp_route);
23025202Skarels 	if (rt = inp->inp_route.ro_rt)
23125202Skarels 	    ifp = rt->rt_ifp;
23225202Skarels     }
23325202Skarels     else
23425202Skarels     {
23525202Skarels 	if (rt = ip_route(&inp->inp_laddr, &sin->sin_addr))
23625202Skarels 	{
23725202Skarels 	    inp->inp_route.ro_rt = rt;
23825202Skarels 	    ifp = rt->rt_ifp;
23925202Skarels 	}
24025202Skarels     }
24125202Skarels 
24225202Skarels     if (ifp == NULL)
24325202Skarels 	return (ENETUNREACH);
24425202Skarels 
24525202Skarels     /*
24625202Skarels      * find Internet address structure for this interface.
24725202Skarels      */
24825202Skarels     ia = in_iafromif(ifp);
24925202Skarels 
25025202Skarels     if (ia == NULL)
25125202Skarels 	/* ??? */
25225202Skarels 	return (ENETUNREACH);
25325202Skarels 
25425202Skarels     ifaddr = (struct sockaddr_in *) &ia->ia_addr;
25525202Skarels 
25625202Skarels #ifdef bsd42
25725202Skarels     /*
25825202Skarels      * 8.7.0.2 (on IMP net) can send to 128.11.0.0 (on Ethernet), but
25925202Skarels      * not to 8.0.0.0
26025202Skarels      */
26125202Skarels     if (in_broadcast(sin->sin_addr) &&
26225202Skarels 	iptonet(sin->sin_addr) == iptonet(ifaddr->sin_addr) &&
26325202Skarels 	!(ifp->if_flags & IFF_BROADCAST) )
26425202Skarels     {
26525202Skarels 	if (rt)
26625202Skarels 	{
26725202Skarels 	    rtfree(rt);
26825202Skarels 	    inp->inp_route.ro_rt = NULL;
26925202Skarels 	}
27025202Skarels 	return (EADDRNOTAVAIL);
27125202Skarels     }
27225202Skarels #endif
27325202Skarels 
27425202Skarels     if ((*conn_used)(inp,
27525202Skarels 	inp->inp_lport,
27625202Skarels 	(inp->inp_laddr.s_addr ? inp->inp_laddr.s_addr : ifaddr->sin_addr.s_addr),
27725202Skarels 	sin->sin_port,
27825202Skarels 	sin->sin_addr.s_addr) != (char *)NULL)
27925202Skarels     {
28025202Skarels 
28125202Skarels 	if (rt)
28225202Skarels 	{
28325202Skarels 	    rtfree(rt);
28425202Skarels 	    inp->inp_route.ro_rt = NULL;
28525202Skarels 	}
28625202Skarels 	return (EADDRINUSE);
28725202Skarels     }
28825202Skarels 
28925202Skarels     if (inp->inp_laddr.s_addr == INADDR_ANY)
29025202Skarels 	inp->inp_laddr = ifaddr->sin_addr;
29125202Skarels     inp->inp_faddr = sin->sin_addr;
29225202Skarels     inp->inp_fport = sin->sin_port;
29325202Skarels     return (0);
29425202Skarels }
29525202Skarels 
29625202Skarels in_pcbdisconnect(inp, pcb_free_func)
29725202Skarels struct inpcb *inp;
29825202Skarels int (*pcb_free_func)();
29925202Skarels {
30025202Skarels     inp->inp_faddr.s_addr = INADDR_ANY;
30125202Skarels     inp->inp_fport = 0;
30225202Skarels     /*
30325202Skarels      * may attach a route to an inpcb several times.  For example,
30425202Skarels      * when UDP does unconnected, but bound, sends.
30525202Skarels      */
30625202Skarels     if (inp->inp_route.ro_rt)
30725202Skarels     {
30825202Skarels 	rtfree(inp->inp_route.ro_rt);
30925202Skarels 	inp->inp_route.ro_rt = NULL;
31025202Skarels     }
31125202Skarels 
31225202Skarels     if (inp->inp_socket->so_state & SS_NOFDREF)
31325202Skarels 	in_pcbdetach(inp, pcb_free_func);
31425202Skarels }
31525202Skarels 
31625202Skarels /*
31725202Skarels  * Don't need to splnet while altering lists, since called from places
31825202Skarels  * where that has already been done.
31925202Skarels  */
in_pcbdetach(inp,pcb_free_func)32025202Skarels in_pcbdetach(inp, pcb_free_func)
32125202Skarels register struct inpcb *inp;
32225202Skarels int (*pcb_free_func)();
32325202Skarels {
32425202Skarels     register struct socket *so;
32525202Skarels 
32625202Skarels     if (so = inp->inp_socket)
32725202Skarels     {
32825202Skarels 	so->so_pcb = (caddr_t) NULL;
32925202Skarels 	/* inp->inp_socket = (struct socket *) NULL; */
33025202Skarels 	soisdisconnected(so);
33125202Skarels 	sofree(so);
33225202Skarels     }
33325202Skarels     else
33425202Skarels 	panic("in_pcbdetach");
33525202Skarels 
33625202Skarels     if (inp->inp_route.ro_rt)
33725202Skarels 	rtfree(inp->inp_route.ro_rt);
33825202Skarels 
33925202Skarels     if (inp->inp_ppcb)
34025202Skarels 	(*pcb_free_func)(inp); /* free per-protocol block */
34125202Skarels 
34225202Skarels     remque(inp);
34325202Skarels 
34425202Skarels     (void) m_free(dtom(inp));
34525202Skarels }
34625202Skarels 
in_setsockaddr(inp,nam)34725202Skarels in_setsockaddr(inp, nam)
34825202Skarels register struct inpcb *inp;
34925202Skarels struct mbuf *nam;
35025202Skarels {
35125202Skarels     register struct sockaddr_in *sin;
35225202Skarels 
35325202Skarels     nam->m_len = sizeof (*sin);
35425202Skarels     sin = mtod(nam, struct sockaddr_in *);
35525202Skarels     bzero((caddr_t)sin, sizeof (*sin));
35625202Skarels     sin->sin_family = AF_INET;
35725202Skarels     sin->sin_port = inp->inp_lport;
35825202Skarels     sin->sin_addr = inp->inp_laddr;
35925202Skarels }
36025202Skarels 
in_setpeeraddr(inp,nam)36125202Skarels in_setpeeraddr(inp, nam)
36225202Skarels register struct inpcb *inp;
36325202Skarels struct mbuf *nam;
36425202Skarels {
36525202Skarels     register struct sockaddr_in *sin;
36625202Skarels 
36725202Skarels     nam->m_len = sizeof (*sin);
36825202Skarels     sin = mtod(nam, struct sockaddr_in *);
36925202Skarels     bzero((caddr_t)sin, sizeof (*sin));
37025202Skarels     sin->sin_family = AF_INET;
37125202Skarels     sin->sin_port = inp->inp_fport;
37225202Skarels     sin->sin_addr = inp->inp_faddr;
37325202Skarels }
37425202Skarels 
37525202Skarels /*
37625202Skarels  * somewhat different from the one in 4.2 and (I think) substantially
37725202Skarels  * easier to read, though a bit slower.
37825202Skarels  *
37925202Skarels  * fport == 0 if don't want/need match on remote port # (HMP and UDP)
38025202Skarels  */
38125202Skarels struct inpcb *
in_pcblookup(head,faddr,fport,laddr,lport,wild)38225202Skarels in_pcblookup(head,faddr,fport,laddr,lport,wild)
38325202Skarels struct inpcb *head;
38425202Skarels u_long faddr, laddr;
38525202Skarels u_short fport, lport;
38625202Skarels int wild;
38725202Skarels {
38825202Skarels     register struct inpcb *inp;
38925202Skarels 
39025202Skarels     /* try exact match */
39125202Skarels     for(inp = head->inp_next; inp != head; inp = inp->inp_next)
39225202Skarels     {
39325202Skarels 	/* ports check */
39425202Skarels 	if (inp->inp_lport != lport)
39525202Skarels 	    continue;
39625202Skarels 
39725202Skarels 	if (fport && (inp->inp_fport != fport))
39825202Skarels 	    continue;
39925202Skarels 
40025202Skarels 	if ((inp->inp_faddr.s_addr != faddr) || (inp->inp_laddr.s_addr != laddr))
40125202Skarels 	    continue;
40225202Skarels 
40325202Skarels 	/* keep it! */
40425202Skarels 	return(inp);
40525202Skarels     }
40625202Skarels 
40725202Skarels     /* try wildcard ? */
40825202Skarels     if (wild)
40925202Skarels     {
41025202Skarels 	for(inp = head->inp_next; inp != head; inp = inp->inp_next)
41125202Skarels 	{
41225202Skarels 	    /* ports again */
41325202Skarels 	    if (inp->inp_lport != lport)
41425202Skarels 		continue;
41525202Skarels 
41625202Skarels 	    if (fport && (inp->inp_fport != fport) && inp->inp_fport)
41725202Skarels 		continue;
41825202Skarels 
41925202Skarels 	    if ((inp->inp_faddr.s_addr) && (inp->inp_faddr.s_addr != faddr))
42025202Skarels 		continue;
42125202Skarels 
42225202Skarels 	    if ((inp->inp_laddr.s_addr) && (inp->inp_laddr.s_addr != laddr))
42325202Skarels 		continue;
42425202Skarels 
42525202Skarels 	    return(inp);
42625202Skarels 	}
42725202Skarels     }
42825202Skarels 
42925202Skarels     return((struct inpcb *) NULL);
43025202Skarels }
43125202Skarels 
43225202Skarels 
43325202Skarels /*
43425202Skarels  * This only advises process and does not internally close socket,
43525202Skarels  * not so much because the user can do much but close when he gets a
43625202Skarels  * HOSTDEAD/HOSTUNREACH indication, but because it is possible that
43725202Skarels  * the destination host has saved connection state information. (His IMP
43825202Skarels  * interface went down for PM, but the machine stayed up...)
43925202Skarels  *
44025202Skarels  * Also, this makes addition of new protocols easy, since we don't need to
44125202Skarels  * know the name and calling sequence of their close/abort routine.
44225202Skarels  *
44325202Skarels  * We do not close child sockets of listen(2)ers for connection oriented
44425202Skarels  * protocols.  We let the protocol do that by timing out connection
44525202Skarels  * establishment.
44625202Skarels  */
inpcb_notify(head,laddr,faddr,error)44725202Skarels inpcb_notify(head, laddr, faddr, error)
44825202Skarels register struct inpcb *head;
44925202Skarels register u_long	laddr;
45025202Skarels register u_long	faddr;
45125202Skarels {
45225202Skarels     register struct inpcb   *inp;
45325202Skarels 
45425202Skarels     for(inp = head->inp_next; inp != head; inp = inp->inp_next)
45525202Skarels 	if (((inp->inp_faddr.s_addr == faddr) || (faddr == 0)) &&
45625202Skarels 	    ((inp->inp_laddr.s_addr == laddr) || (laddr == 0)))
45725202Skarels 		advise_user(inp->inp_socket, error);
45825202Skarels }
45925202Skarels 
46025202Skarels advise_user(so, error)
46125202Skarels struct socket *so;
46225202Skarels int error;
46325202Skarels {
46425202Skarels     if (so == 0)
46525202Skarels 	return;
46625202Skarels 
46725202Skarels     so->so_error = error;
46825202Skarels 
46925202Skarels     wakeup((caddr_t) &so->so_timeo); /* in connect(2) */
47025202Skarels     sowwakeup(so);
47125202Skarels     sorwakeup(so);
47225202Skarels }
473