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