xref: /csrg-svn/sys/deprecated/bbnnet/in_pcb.c (revision 25202)
1*25202Skarels #ifdef	RCSIDENT
2*25202Skarels static char rcsident[] = "$Header: in_pcb.c,v 1.12 84/11/29 17:02:13 walsh Exp $";
3*25202Skarels #endif	RCSIDENT
4*25202Skarels 
5*25202Skarels #include "../h/param.h"
6*25202Skarels #include "../h/systm.h"
7*25202Skarels #include "../h/dir.h"
8*25202Skarels #include "../h/user.h"
9*25202Skarels #include "../h/mbuf.h"
10*25202Skarels #include "../h/socket.h"
11*25202Skarels #include "../h/socketvar.h"
12*25202Skarels #include "../h/protosw.h"
13*25202Skarels #include "../h/domain.h"
14*25202Skarels 
15*25202Skarels #include "../net/if.h"
16*25202Skarels #include "../net/route.h"
17*25202Skarels 
18*25202Skarels #include "../bbnnet/in.h"
19*25202Skarels #include "../bbnnet/net.h"
20*25202Skarels #include "../bbnnet/in_pcb.h"
21*25202Skarels #include "../bbnnet/in_var.h"
22*25202Skarels 
23*25202Skarels extern struct rtentry *ip_route();
24*25202Skarels extern struct domain  inetdomain;
25*25202Skarels 
26*25202Skarels in_pcballoc(so, head)
27*25202Skarels struct socket *so;
28*25202Skarels struct inpcb *head;
29*25202Skarels {
30*25202Skarels     register struct mbuf *m;
31*25202Skarels     register struct inpcb *inp;
32*25202Skarels 
33*25202Skarels     m = m_getclr(M_DONTWAIT, MT_PCB);
34*25202Skarels     if (m == NULL)
35*25202Skarels 	return (ENOBUFS);
36*25202Skarels 
37*25202Skarels     inp = mtod(m, struct inpcb *);
38*25202Skarels     inp->inp_socket = so;
39*25202Skarels 
40*25202Skarels     insque(inp,head);
41*25202Skarels 
42*25202Skarels     so->so_pcb = (caddr_t)inp;
43*25202Skarels 
44*25202Skarels     return (0);
45*25202Skarels }
46*25202Skarels 
47*25202Skarels /*
48*25202Skarels  * changed from 4.2 to accept a structure which has protocol
49*25202Skarels  * specific data like how to break down port allocation.
50*25202Skarels  */
51*25202Skarels 
52*25202Skarels in_pcbbind(inp, nam, advice)
53*25202Skarels register struct inpcb *inp;
54*25202Skarels struct mbuf *nam;
55*25202Skarels struct pr_advice *advice;
56*25202Skarels {
57*25202Skarels     register struct socket *so = inp->inp_socket;
58*25202Skarels     register struct sockaddr_in *sin;
59*25202Skarels     register u_short lport = 0;
60*25202Skarels 
61*25202Skarels     if (in_ifaddr == NULL)
62*25202Skarels 	return (EADDRNOTAVAIL);
63*25202Skarels     /*
64*25202Skarels      * socket must not already be bound
65*25202Skarels      */
66*25202Skarels 
67*25202Skarels     if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY)
68*25202Skarels 	return (EINVAL);
69*25202Skarels 
70*25202Skarels     if (nam == 0)
71*25202Skarels 	goto noname;
72*25202Skarels     sin = mtod(nam, struct sockaddr_in *);
73*25202Skarels     if (nam->m_len != sizeof (*sin))
74*25202Skarels 	return (EINVAL);
75*25202Skarels     /*
76*25202Skarels      * Since Berkeley left this out, some of their programs (ftpd)
77*25202Skarels      * aren't ready for it
78*25202Skarels      *
79*25202Skarels     if (sin->sin_family != AF_INET)
80*25202Skarels 	    return (EAFNOSUPPORT);
81*25202Skarels      */
82*25202Skarels 
83*25202Skarels     if (sin->sin_addr.s_addr != INADDR_ANY)
84*25202Skarels     {
85*25202Skarels 	/* some code says ..withnet() */
86*25202Skarels 	if (in_iawithaddr(sin->sin_addr, FALSE) == NULL)
87*25202Skarels 	    return (EADDRNOTAVAIL);
88*25202Skarels 
89*25202Skarels     }
90*25202Skarels 
91*25202Skarels     /* user gives port to us in net order */
92*25202Skarels     if (lport = sin->sin_port)
93*25202Skarels     {
94*25202Skarels 	u_short aport;
95*25202Skarels 
96*25202Skarels 	/* if portsize > 2 a major rewrite needed to
97*25202Skarels 	 * accomodate longs.....
98*25202Skarels 	 */
99*25202Skarels 
100*25202Skarels 	if (advice->portsize > 1)
101*25202Skarels 	    aport = ntohs(lport);
102*25202Skarels 	else
103*25202Skarels 	    aport = lport;	/* a char is a char */
104*25202Skarels 
105*25202Skarels 	/*
106*25202Skarels 	 *  really only a worry for byte size ports
107*25202Skarels 	 */
108*25202Skarels 
109*25202Skarels 	if (aport > advice->maxport)
110*25202Skarels 	    return(EADDRNOTAVAIL);
111*25202Skarels 
112*25202Skarels 	if (aport <= advice->rootport && u.u_uid != 0)
113*25202Skarels 	    return (EACCES);
114*25202Skarels 
115*25202Skarels 	/*
116*25202Skarels 	 * Check to see if the local address/port is in use.
117*25202Skarels 	 * but, process may use this pair to communicate with
118*25202Skarels 	 * several destinations (each with its own tcp) if he
119*25202Skarels 	 * sets SO_REUSEADDR
120*25202Skarels 	 */
121*25202Skarels 	if (advice->bind_used &&
122*25202Skarels 	    (*(advice->bind_used))(inp,		/* current binding */
123*25202Skarels 	    lport,			/* desired port */
124*25202Skarels 	    sin->sin_addr.s_addr,	/* desired address */
125*25202Skarels 	    so->so_options & SO_REUSEADDR))
126*25202Skarels 	{
127*25202Skarels 	    return (EADDRINUSE);
128*25202Skarels 	}
129*25202Skarels     }
130*25202Skarels     inp->inp_laddr = sin->sin_addr;
131*25202Skarels 
132*25202Skarels noname :
133*25202Skarels     /* any ports for random allocation by non-root users? */
134*25202Skarels     if ((advice->maxport <= advice->resvport) && (u.u_uid))
135*25202Skarels 	return(EADDRNOTAVAIL);
136*25202Skarels 
137*25202Skarels     if (lport == 0)
138*25202Skarels     {
139*25202Skarels 	/*
140*25202Skarels 	 * Allow for reserved ports for non-super users
141*25202Skarels 	 * so that don't interfere with some project's software.
142*25202Skarels 	 */
143*25202Skarels 	u_short possible = advice->nowport;
144*25202Skarels 
145*25202Skarels 	do
146*25202Skarels 	{
147*25202Skarels 	    if (advice->portsize > 1)
148*25202Skarels 		lport = htons(possible);
149*25202Skarels 	    else
150*25202Skarels 		lport = possible;
151*25202Skarels 
152*25202Skarels 	    /*
153*25202Skarels 	     * catch roll over.....
154*25202Skarels 	     */
155*25202Skarels 
156*25202Skarels 	    if (possible >= advice->maxport)
157*25202Skarels 		possible = advice->resvport + 1;
158*25202Skarels 	    else
159*25202Skarels 		possible++;
160*25202Skarels 
161*25202Skarels 	    /*
162*25202Skarels 	     * no free ports??? RDP/HMP problem
163*25202Skarels 	     */
164*25202Skarels 
165*25202Skarels 	    if (possible == advice->nowport)
166*25202Skarels 		return(EADDRNOTAVAIL);
167*25202Skarels 
168*25202Skarels 	}
169*25202Skarels 	while (advice->bind_used &&
170*25202Skarels 	    (*(advice->bind_used))(inp, lport, inp->inp_laddr.s_addr, 0));
171*25202Skarels 
172*25202Skarels 	advice->nowport = possible;
173*25202Skarels     }
174*25202Skarels     inp->inp_lport = lport;
175*25202Skarels     return (0);
176*25202Skarels }
177*25202Skarels 
178*25202Skarels /*
179*25202Skarels  * Connect from a socket to a specified address.
180*25202Skarels  * Both address and port must be specified in argument sin.
181*25202Skarels  * If don't have a local address for this socket yet,
182*25202Skarels  * then pick one.
183*25202Skarels  */
184*25202Skarels in_pcbconnect(inp, nam, conn_used)
185*25202Skarels struct inpcb *inp;
186*25202Skarels struct mbuf *nam;
187*25202Skarels char *(*conn_used)();
188*25202Skarels {
189*25202Skarels     register struct ifnet *ifp = NULL;
190*25202Skarels     register struct in_ifaddr *ia = NULL;
191*25202Skarels     register struct sockaddr_in *ifaddr;
192*25202Skarels     register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
193*25202Skarels     register struct rtentry *rt;
194*25202Skarels     struct sockaddr_in *inpsin;
195*25202Skarels 
196*25202Skarels     if (nam->m_len != sizeof (*sin))
197*25202Skarels 	return (EINVAL);
198*25202Skarels     if (sin->sin_family != AF_INET)
199*25202Skarels 	return (EAFNOSUPPORT);
200*25202Skarels     if (sin->sin_addr.s_addr == INADDR_ANY || sin->sin_port == 0)
201*25202Skarels 	return (EADDRNOTAVAIL);
202*25202Skarels 
203*25202Skarels     /*
204*25202Skarels      * Find route for connection.  For a tcp connecting to a server,
205*25202Skarels      * this route will be used for the duration of the connection
206*25202Skarels      * (unless redirected...).  For a UDP doing a connect, this route
207*25202Skarels      * will also be used for the duration.  For a UDP unconnected send,
208*25202Skarels      * this route will be used for the current packet.
209*25202Skarels      *
210*25202Skarels      * rtalloc cannot handle routing with both sides already bound
211*25202Skarels      */
212*25202Skarels     rt = (struct rtentry *) NULL;
213*25202Skarels 
214*25202Skarels     /*
215*25202Skarels      * NOTE: programmers often forget to zero sin_zero[0-1].
216*25202Skarels      * rtalloc does not want to know the port number for routes to hosts.
217*25202Skarels      */
218*25202Skarels     inpsin = (struct sockaddr_in *) &inp->inp_route.ro_dst;
219*25202Skarels     bcopy((caddr_t)sin, (caddr_t)inpsin, sizeof (*sin));
220*25202Skarels     inpsin->sin_port = 0;
221*25202Skarels 
222*25202Skarels     if (inp->inp_laddr.s_addr == INADDR_ANY)
223*25202Skarels     {
224*25202Skarels 	rtalloc(&inp->inp_route);
225*25202Skarels 	if (rt = inp->inp_route.ro_rt)
226*25202Skarels 	    ifp = rt->rt_ifp;
227*25202Skarels     }
228*25202Skarels     else
229*25202Skarels     {
230*25202Skarels 	if (rt = ip_route(&inp->inp_laddr, &sin->sin_addr))
231*25202Skarels 	{
232*25202Skarels 	    inp->inp_route.ro_rt = rt;
233*25202Skarels 	    ifp = rt->rt_ifp;
234*25202Skarels 	}
235*25202Skarels     }
236*25202Skarels 
237*25202Skarels     if (ifp == NULL)
238*25202Skarels 	return (ENETUNREACH);
239*25202Skarels 
240*25202Skarels     /*
241*25202Skarels      * find Internet address structure for this interface.
242*25202Skarels      */
243*25202Skarels     ia = in_iafromif(ifp);
244*25202Skarels 
245*25202Skarels     if (ia == NULL)
246*25202Skarels 	/* ??? */
247*25202Skarels 	return (ENETUNREACH);
248*25202Skarels 
249*25202Skarels     ifaddr = (struct sockaddr_in *) &ia->ia_addr;
250*25202Skarels 
251*25202Skarels #ifdef bsd42
252*25202Skarels     /*
253*25202Skarels      * 8.7.0.2 (on IMP net) can send to 128.11.0.0 (on Ethernet), but
254*25202Skarels      * not to 8.0.0.0
255*25202Skarels      */
256*25202Skarels     if (in_broadcast(sin->sin_addr) &&
257*25202Skarels 	iptonet(sin->sin_addr) == iptonet(ifaddr->sin_addr) &&
258*25202Skarels 	!(ifp->if_flags & IFF_BROADCAST) )
259*25202Skarels     {
260*25202Skarels 	if (rt)
261*25202Skarels 	{
262*25202Skarels 	    rtfree(rt);
263*25202Skarels 	    inp->inp_route.ro_rt = NULL;
264*25202Skarels 	}
265*25202Skarels 	return (EADDRNOTAVAIL);
266*25202Skarels     }
267*25202Skarels #endif
268*25202Skarels 
269*25202Skarels     if ((*conn_used)(inp,
270*25202Skarels 	inp->inp_lport,
271*25202Skarels 	(inp->inp_laddr.s_addr ? inp->inp_laddr.s_addr : ifaddr->sin_addr.s_addr),
272*25202Skarels 	sin->sin_port,
273*25202Skarels 	sin->sin_addr.s_addr) != (char *)NULL)
274*25202Skarels     {
275*25202Skarels 
276*25202Skarels 	if (rt)
277*25202Skarels 	{
278*25202Skarels 	    rtfree(rt);
279*25202Skarels 	    inp->inp_route.ro_rt = NULL;
280*25202Skarels 	}
281*25202Skarels 	return (EADDRINUSE);
282*25202Skarels     }
283*25202Skarels 
284*25202Skarels     if (inp->inp_laddr.s_addr == INADDR_ANY)
285*25202Skarels 	inp->inp_laddr = ifaddr->sin_addr;
286*25202Skarels     inp->inp_faddr = sin->sin_addr;
287*25202Skarels     inp->inp_fport = sin->sin_port;
288*25202Skarels     return (0);
289*25202Skarels }
290*25202Skarels 
291*25202Skarels in_pcbdisconnect(inp, pcb_free_func)
292*25202Skarels struct inpcb *inp;
293*25202Skarels int (*pcb_free_func)();
294*25202Skarels {
295*25202Skarels     inp->inp_faddr.s_addr = INADDR_ANY;
296*25202Skarels     inp->inp_fport = 0;
297*25202Skarels     /*
298*25202Skarels      * may attach a route to an inpcb several times.  For example,
299*25202Skarels      * when UDP does unconnected, but bound, sends.
300*25202Skarels      */
301*25202Skarels     if (inp->inp_route.ro_rt)
302*25202Skarels     {
303*25202Skarels 	rtfree(inp->inp_route.ro_rt);
304*25202Skarels 	inp->inp_route.ro_rt = NULL;
305*25202Skarels     }
306*25202Skarels 
307*25202Skarels     if (inp->inp_socket->so_state & SS_NOFDREF)
308*25202Skarels 	in_pcbdetach(inp, pcb_free_func);
309*25202Skarels }
310*25202Skarels 
311*25202Skarels /*
312*25202Skarels  * Don't need to splnet while altering lists, since called from places
313*25202Skarels  * where that has already been done.
314*25202Skarels  */
315*25202Skarels in_pcbdetach(inp, pcb_free_func)
316*25202Skarels register struct inpcb *inp;
317*25202Skarels int (*pcb_free_func)();
318*25202Skarels {
319*25202Skarels     register struct socket *so;
320*25202Skarels 
321*25202Skarels     if (so = inp->inp_socket)
322*25202Skarels     {
323*25202Skarels 	so->so_pcb = (caddr_t) NULL;
324*25202Skarels 	/* inp->inp_socket = (struct socket *) NULL; */
325*25202Skarels 	soisdisconnected(so);
326*25202Skarels 	sofree(so);
327*25202Skarels     }
328*25202Skarels     else
329*25202Skarels 	panic("in_pcbdetach");
330*25202Skarels 
331*25202Skarels     if (inp->inp_route.ro_rt)
332*25202Skarels 	rtfree(inp->inp_route.ro_rt);
333*25202Skarels 
334*25202Skarels     if (inp->inp_ppcb)
335*25202Skarels 	(*pcb_free_func)(inp); /* free per-protocol block */
336*25202Skarels 
337*25202Skarels     remque(inp);
338*25202Skarels 
339*25202Skarels     (void) m_free(dtom(inp));
340*25202Skarels }
341*25202Skarels 
342*25202Skarels in_setsockaddr(inp, nam)
343*25202Skarels register struct inpcb *inp;
344*25202Skarels struct mbuf *nam;
345*25202Skarels {
346*25202Skarels     register struct sockaddr_in *sin;
347*25202Skarels 
348*25202Skarels     nam->m_len = sizeof (*sin);
349*25202Skarels     sin = mtod(nam, struct sockaddr_in *);
350*25202Skarels     bzero((caddr_t)sin, sizeof (*sin));
351*25202Skarels     sin->sin_family = AF_INET;
352*25202Skarels     sin->sin_port = inp->inp_lport;
353*25202Skarels     sin->sin_addr = inp->inp_laddr;
354*25202Skarels }
355*25202Skarels 
356*25202Skarels in_setpeeraddr(inp, nam)
357*25202Skarels register struct inpcb *inp;
358*25202Skarels struct mbuf *nam;
359*25202Skarels {
360*25202Skarels     register struct sockaddr_in *sin;
361*25202Skarels 
362*25202Skarels     nam->m_len = sizeof (*sin);
363*25202Skarels     sin = mtod(nam, struct sockaddr_in *);
364*25202Skarels     bzero((caddr_t)sin, sizeof (*sin));
365*25202Skarels     sin->sin_family = AF_INET;
366*25202Skarels     sin->sin_port = inp->inp_fport;
367*25202Skarels     sin->sin_addr = inp->inp_faddr;
368*25202Skarels }
369*25202Skarels 
370*25202Skarels /*
371*25202Skarels  * somewhat different from the one in 4.2 and (I think) substantially
372*25202Skarels  * easier to read, though a bit slower.
373*25202Skarels  *
374*25202Skarels  * fport == 0 if don't want/need match on remote port # (HMP and UDP)
375*25202Skarels  */
376*25202Skarels struct inpcb *
377*25202Skarels in_pcblookup(head,faddr,fport,laddr,lport,wild)
378*25202Skarels struct inpcb *head;
379*25202Skarels u_long faddr, laddr;
380*25202Skarels u_short fport, lport;
381*25202Skarels int wild;
382*25202Skarels {
383*25202Skarels     register struct inpcb *inp;
384*25202Skarels 
385*25202Skarels     /* try exact match */
386*25202Skarels     for(inp = head->inp_next; inp != head; inp = inp->inp_next)
387*25202Skarels     {
388*25202Skarels 	/* ports check */
389*25202Skarels 	if (inp->inp_lport != lport)
390*25202Skarels 	    continue;
391*25202Skarels 
392*25202Skarels 	if (fport && (inp->inp_fport != fport))
393*25202Skarels 	    continue;
394*25202Skarels 
395*25202Skarels 	if ((inp->inp_faddr.s_addr != faddr) || (inp->inp_laddr.s_addr != laddr))
396*25202Skarels 	    continue;
397*25202Skarels 
398*25202Skarels 	/* keep it! */
399*25202Skarels 	return(inp);
400*25202Skarels     }
401*25202Skarels 
402*25202Skarels     /* try wildcard ? */
403*25202Skarels     if (wild)
404*25202Skarels     {
405*25202Skarels 	for(inp = head->inp_next; inp != head; inp = inp->inp_next)
406*25202Skarels 	{
407*25202Skarels 	    /* ports again */
408*25202Skarels 	    if (inp->inp_lport != lport)
409*25202Skarels 		continue;
410*25202Skarels 
411*25202Skarels 	    if (fport && (inp->inp_fport != fport) && inp->inp_fport)
412*25202Skarels 		continue;
413*25202Skarels 
414*25202Skarels 	    if ((inp->inp_faddr.s_addr) && (inp->inp_faddr.s_addr != faddr))
415*25202Skarels 		continue;
416*25202Skarels 
417*25202Skarels 	    if ((inp->inp_laddr.s_addr) && (inp->inp_laddr.s_addr != laddr))
418*25202Skarels 		continue;
419*25202Skarels 
420*25202Skarels 	    return(inp);
421*25202Skarels 	}
422*25202Skarels     }
423*25202Skarels 
424*25202Skarels     return((struct inpcb *) NULL);
425*25202Skarels }
426*25202Skarels 
427*25202Skarels 
428*25202Skarels /*
429*25202Skarels  * This only advises process and does not internally close socket,
430*25202Skarels  * not so much because the user can do much but close when he gets a
431*25202Skarels  * HOSTDEAD/HOSTUNREACH indication, but because it is possible that
432*25202Skarels  * the destination host has saved connection state information. (His IMP
433*25202Skarels  * interface went down for PM, but the machine stayed up...)
434*25202Skarels  *
435*25202Skarels  * Also, this makes addition of new protocols easy, since we don't need to
436*25202Skarels  * know the name and calling sequence of their close/abort routine.
437*25202Skarels  *
438*25202Skarels  * We do not close child sockets of listen(2)ers for connection oriented
439*25202Skarels  * protocols.  We let the protocol do that by timing out connection
440*25202Skarels  * establishment.
441*25202Skarels  */
442*25202Skarels inpcb_notify(head, laddr, faddr, error)
443*25202Skarels register struct inpcb *head;
444*25202Skarels register u_long	laddr;
445*25202Skarels register u_long	faddr;
446*25202Skarels {
447*25202Skarels     register struct inpcb   *inp;
448*25202Skarels 
449*25202Skarels     for(inp = head->inp_next; inp != head; inp = inp->inp_next)
450*25202Skarels 	if (((inp->inp_faddr.s_addr == faddr) || (faddr == 0)) &&
451*25202Skarels 	    ((inp->inp_laddr.s_addr == laddr) || (laddr == 0)))
452*25202Skarels 		advise_user(inp->inp_socket, error);
453*25202Skarels }
454*25202Skarels 
455*25202Skarels advise_user(so, error)
456*25202Skarels struct socket *so;
457*25202Skarels int error;
458*25202Skarels {
459*25202Skarels     if (so == 0)
460*25202Skarels 	return;
461*25202Skarels 
462*25202Skarels     so->so_error = error;
463*25202Skarels 
464*25202Skarels     wakeup((caddr_t) &so->so_timeo); /* in connect(2) */
465*25202Skarels     sowwakeup(so);
466*25202Skarels     sorwakeup(so);
467*25202Skarels }
468