xref: /csrg-svn/sys/netinet/in_pcb.c (revision 5161)
1*5161Swnj /* in_pcb.c 4.11 81/12/02 */
24905Swnj 
34905Swnj #include "../h/param.h"
44951Swnj #include "../h/systm.h"
54951Swnj #include "../h/dir.h"
64951Swnj #include "../h/user.h"
74905Swnj #include "../h/mbuf.h"
84905Swnj #include "../h/socket.h"
94905Swnj #include "../h/socketvar.h"
105084Swnj #include "../net/in.h"
115084Swnj #include "../net/in_systm.h"
124951Swnj #include "../net/if.h"
135084Swnj #include "../net/in_pcb.h"
144905Swnj 
154951Swnj /*
16*5161Swnj  * Routines to manage internet protocol control blocks.
17*5161Swnj  *
18*5161Swnj  * At PRU_ATTACH time a protocol control block is allocated in
19*5161Swnj  * in_pcballoc() and inserted on a doubly-linked list of such blocks
20*5161Swnj  * for the protocol.  A port address is either requested (and verified
21*5161Swnj  * to not be in use) or assigned at this time.  We also allocate
22*5161Swnj  * space in the socket sockbuf structures here, although this is
23*5161Swnj  * not a clearly correct place to put this function.
24*5161Swnj  *
25*5161Swnj  * A connectionless protocol will have its protocol control block
26*5161Swnj  * removed at PRU_DETACH time, when the socket will be freed (freeing
27*5161Swnj  * the space reserved) and the block will be removed from the list of
28*5161Swnj  * blocks for its protocol.
29*5161Swnj  *
30*5161Swnj  * A connection-based protocol may be connected to a remote peer at
31*5161Swnj  * PRU_CONNECT time through the routine in_pcbconnect().  In the normal
32*5161Swnj  * case a PRU_DISCONNECT occurs causing a in_pcbdisconnect().
33*5161Swnj  * It is also possible that higher-level routines will opt out of the
34*5161Swnj  * relationship with the connection before the connection shut down
35*5161Swnj  * is complete.  This often occurs in protocols like TCP where we must
36*5161Swnj  * hold on to the protocol control block for a unreasonably long time
37*5161Swnj  * after the connection is used up to avoid races in later connection
38*5161Swnj  * establishment.  To handle this we allow higher-level routines to
39*5161Swnj  * disassociate themselves from the socket, marking it SS_USERGONE while
40*5161Swnj  * the disconnect is in progress.  We notice that this has happened
41*5161Swnj  * when the disconnect is complete, and perform the PRU_DETACH operation,
42*5161Swnj  * freeing the socket.
43*5161Swnj  */
44*5161Swnj 
45*5161Swnj /*
464951Swnj  * Allocate a protocol control block, space
474951Swnj  * for send and receive data, and local host information.
484951Swnj  * Return error.  If no error make socket point at pcb.
494951Swnj  */
50*5161Swnj in_pcbattach(so, head, sndcc, rcvcc, sin)
514951Swnj 	struct socket *so;
524951Swnj 	struct inpcb *head;
534951Swnj 	int sndcc, rcvcc;
544951Swnj 	struct sockaddr_in *sin;
554905Swnj {
564905Swnj 	struct mbuf *m;
574983Swnj 	register struct inpcb *inp, *xp;
584951Swnj 	struct ifnet *ifp;
594951Swnj 	u_long lport;
604905Swnj 
61*5161Swnj COUNT(IN_PCBATTACH);
624951Swnj 	if (sin) {
634951Swnj 		if (sin->sin_family != AF_INET)
644951Swnj 			return (EAFNOSUPPORT);
654951Swnj 		ifp = if_ifwithaddr(sin->sin_addr);
664951Swnj 		if (ifp == 0)
674951Swnj 			return (EADDRNOTAVAIL);
684951Swnj 		lport = sin->sin_port;
694951Swnj 		if (lport) {
704983Swnj 			xp = head->inp_next;
715107Swnj 			for (; xp != head; xp = xp->inp_next)
724983Swnj 				if (xp->inp_laddr.s_addr ==
734951Swnj 				    sin->sin_addr.s_addr &&
744983Swnj 				    xp->inp_lport == lport &&
754983Swnj 				    xp->inp_faddr.s_addr == 0)
764951Swnj 					return (EADDRINUSE);
774951Swnj 		}
784951Swnj 	} else {
794951Swnj 		ifp = if_ifwithaddr(ifnet->if_addr);
804951Swnj 		lport = 0;
814951Swnj 	}
824905Swnj 	m = m_getclr(M_WAIT);
834951Swnj 	if (m == 0)
844983Swnj 		return (ENOBUFS);
854951Swnj 	if (sbreserve(&so->so_snd, sndcc) == 0)
864951Swnj 		goto bad;
874951Swnj 	if (sbreserve(&so->so_rcv, rcvcc) == 0)
884951Swnj 		goto bad2;
894951Swnj 	inp = mtod(m, struct inpcb *);
904951Swnj 	inp->inp_laddr = ifp->if_addr;
914951Swnj 	if (lport)
924951Swnj 		goto gotport;
934951Swnj again:
944951Swnj 	if (head->inp_lport++ < 1024)
954951Swnj 		head->inp_lport = 1024;
964983Swnj 	for (xp = head->inp_next; xp != head; xp = xp->inp_next)
974983Swnj 		if (xp->inp_lport == head->inp_lport)
984951Swnj 			goto again;
99*5161Swnj 	lport = htons(head->inp_lport);
1004951Swnj gotport:
1014983Swnj 	inp->inp_socket = so;
1024951Swnj 	inp->inp_lport = lport;
1034983Swnj 	insque(inp, head);
1044951Swnj 	so->so_pcb = (caddr_t)inp;
1054958Swnj 	sin = (struct sockaddr_in *)&so->so_addr;
1064958Swnj 	sin->sin_family = AF_INET;
1074958Swnj 	sin->sin_addr = inp->inp_laddr;
1084958Swnj 	sin->sin_port = inp->inp_lport;
1094951Swnj 	return (0);
1104951Swnj bad2:
1114951Swnj 	sbrelease(&so->so_snd);
1124951Swnj bad:
1134967Swnj 	(void) m_free(m);
1144951Swnj 	return (ENOBUFS);
1154905Swnj }
1164905Swnj 
117*5161Swnj in_pcbconnect(inp, sin)
1184951Swnj 	struct inpcb *inp;
1194951Swnj 	struct sockaddr_in *sin;
1204923Swnj {
1214923Swnj 
122*5161Swnj COUNT(IN_PCBCONNECT);
1234951Swnj 	if (sin->sin_family != AF_INET)
1244951Swnj 		return (EAFNOSUPPORT);
1254951Swnj 	if (sin->sin_addr.s_addr == 0 || sin->sin_port == 0)
1264951Swnj 		return (EADDRNOTAVAIL);
1274951Swnj 	/* should check not already in use... */
1284951Swnj 	inp->inp_faddr = sin->sin_addr;
1294951Swnj 	inp->inp_fport = sin->sin_port;
1304923Swnj 	return (0);
1314923Swnj }
1324923Swnj 
133*5161Swnj in_pcbdisconnect(inp)
1344905Swnj 	struct inpcb *inp;
1354905Swnj {
136*5161Swnj 
137*5161Swnj COUNT(IN_PCBDISCONNECT);
138*5161Swnj 	inp->inp_faddr.s_addr = 0;
139*5161Swnj 	if (inp->inp_socket->so_state & SS_USERGONE)
140*5161Swnj 		in_pcbdetach(inp);
141*5161Swnj }
142*5161Swnj 
143*5161Swnj in_pcbdetach(inp)
144*5161Swnj 	struct inpcb *inp;
145*5161Swnj {
1464905Swnj 	struct socket *so = inp->inp_socket;
1474905Swnj 
1485009Swnj 	so->so_pcb = 0;
1495009Swnj 	sofree(so);
1504983Swnj 	remque(inp);
1514907Swnj 	(void) m_free(dtom(inp));
1524905Swnj }
1534905Swnj 
154*5161Swnj /*
155*5161Swnj  * Look for a control block to accept a segment.
156*5161Swnj  * First choice is an exact address match.
157*5161Swnj  * Second choice is a match of local address, with
158*5161Swnj  * unspecified foreign address.
159*5161Swnj  */
1604907Swnj struct inpcb *
1614951Swnj in_pcblookup(head, faddr, fport, laddr, lport)
1624905Swnj 	struct inpcb *head;
1634951Swnj 	struct in_addr faddr, laddr;
1644905Swnj 	u_short fport, lport;
1654905Swnj {
1664905Swnj 	register struct inpcb *inp;
167*5161Swnj 	struct inpcb *match = 0;
1684905Swnj 
169*5161Swnj 	for (inp = head->inp_next; inp != head; inp = inp->inp_next) {
170*5161Swnj 		if (inp->inp_laddr.s_addr != laddr.s_addr ||
171*5161Swnj 		    inp->inp_lport != lport)
172*5161Swnj 			continue;
173*5161Swnj 		if (inp->inp_faddr.s_addr == 0) {
174*5161Swnj 			match = inp;
175*5161Swnj 			continue;
176*5161Swnj 		}
1774951Swnj 		if (inp->inp_faddr.s_addr == faddr.s_addr &&
178*5161Swnj 		    inp->inp_fport == fport)
1794905Swnj 			return (inp);
180*5161Swnj 	}
181*5161Swnj 	return (match);
1824905Swnj }
183