xref: /csrg-svn/sys/netinet/in_pcb.c (revision 5084)
1*5084Swnj /* in_pcb.c 4.9 81/11/26 */
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"
10*5084Swnj #include "../net/in.h"
11*5084Swnj #include "../net/in_systm.h"
124951Swnj #include "../net/if.h"
13*5084Swnj #include "../net/in_pcb.h"
144905Swnj 
154951Swnj /*
164951Swnj  * Allocate a protocol control block, space
174951Swnj  * for send and receive data, and local host information.
184951Swnj  * Return error.  If no error make socket point at pcb.
194951Swnj  */
204951Swnj in_pcballoc(so, head, sndcc, rcvcc, sin)
214951Swnj 	struct socket *so;
224951Swnj 	struct inpcb *head;
234951Swnj 	int sndcc, rcvcc;
244951Swnj 	struct sockaddr_in *sin;
254905Swnj {
264905Swnj 	struct mbuf *m;
274983Swnj 	register struct inpcb *inp, *xp;
284951Swnj 	struct ifnet *ifp;
294951Swnj 	u_long lport;
304905Swnj 
314951Swnj 	if (sin) {
324951Swnj 		if (sin->sin_family != AF_INET)
334951Swnj 			return (EAFNOSUPPORT);
344951Swnj 		ifp = if_ifwithaddr(sin->sin_addr);
354951Swnj 		if (ifp == 0)
364951Swnj 			return (EADDRNOTAVAIL);
374951Swnj 		lport = sin->sin_port;
384951Swnj 		if (lport) {
394983Swnj 			xp = head->inp_next;
404983Swnj 			for (; xp != head; xp = inp->inp_next)
414983Swnj 				if (xp->inp_laddr.s_addr ==
424951Swnj 				    sin->sin_addr.s_addr &&
434983Swnj 				    xp->inp_lport == lport &&
444983Swnj 				    xp->inp_faddr.s_addr == 0)
454951Swnj 					return (EADDRINUSE);
464951Swnj 		}
474951Swnj 	} else {
484951Swnj 		ifp = if_ifwithaddr(ifnet->if_addr);
494951Swnj 		lport = 0;
504951Swnj 	}
514905Swnj 	m = m_getclr(M_WAIT);
524951Swnj 	if (m == 0)
534983Swnj 		return (ENOBUFS);
544951Swnj 	if (sbreserve(&so->so_snd, sndcc) == 0)
554951Swnj 		goto bad;
564951Swnj 	if (sbreserve(&so->so_rcv, rcvcc) == 0)
574951Swnj 		goto bad2;
584951Swnj 	inp = mtod(m, struct inpcb *);
594951Swnj 	inp->inp_laddr = ifp->if_addr;
604951Swnj 	if (lport)
614951Swnj 		goto gotport;
624951Swnj again:
634951Swnj 	if (head->inp_lport++ < 1024)
644951Swnj 		head->inp_lport = 1024;
654983Swnj 	for (xp = head->inp_next; xp != head; xp = xp->inp_next)
664983Swnj 		if (xp->inp_lport == head->inp_lport)
674951Swnj 			goto again;
684951Swnj 	lport = head->inp_lport;
694951Swnj gotport:
704983Swnj 	inp->inp_socket = so;
714951Swnj 	inp->inp_lport = lport;
724983Swnj 	insque(inp, head);
734951Swnj 	so->so_pcb = (caddr_t)inp;
744958Swnj 	sin = (struct sockaddr_in *)&so->so_addr;
754958Swnj 	sin->sin_family = AF_INET;
764958Swnj 	sin->sin_addr = inp->inp_laddr;
774958Swnj 	sin->sin_port = inp->inp_lport;
784951Swnj 	return (0);
794951Swnj bad2:
804951Swnj 	sbrelease(&so->so_snd);
814951Swnj bad:
824967Swnj 	(void) m_free(m);
834951Swnj 	return (ENOBUFS);
844905Swnj }
854905Swnj 
864951Swnj in_pcbsetpeer(inp, sin)
874951Swnj 	struct inpcb *inp;
884951Swnj 	struct sockaddr_in *sin;
894923Swnj {
904923Swnj 
914951Swnj 	if (sin->sin_family != AF_INET)
924951Swnj 		return (EAFNOSUPPORT);
934951Swnj 	if (sin->sin_addr.s_addr == 0 || sin->sin_port == 0)
944951Swnj 		return (EADDRNOTAVAIL);
954951Swnj 	/* should check not already in use... */
964951Swnj 	inp->inp_faddr = sin->sin_addr;
974951Swnj 	inp->inp_fport = sin->sin_port;
984923Swnj 	return (0);
994923Swnj }
1004923Swnj 
1014905Swnj in_pcbfree(inp)
1024905Swnj 	struct inpcb *inp;
1034905Swnj {
1044905Swnj 	struct socket *so = inp->inp_socket;
1054905Swnj 
1065009Swnj 	so->so_pcb = 0;
1075009Swnj 	sofree(so);
1084983Swnj 	remque(inp);
1094907Swnj 	(void) m_free(dtom(inp));
1104905Swnj }
1114905Swnj 
1124907Swnj struct inpcb *
1134951Swnj in_pcblookup(head, faddr, fport, laddr, lport)
1144905Swnj 	struct inpcb *head;
1154951Swnj 	struct in_addr faddr, laddr;
1164905Swnj 	u_short fport, lport;
1174905Swnj {
1184905Swnj 	register struct inpcb *inp;
1194905Swnj 
1204907Swnj 	for (inp = head->inp_next; inp != head; inp = inp->inp_next)
1214951Swnj 		if (inp->inp_faddr.s_addr == faddr.s_addr &&
1224905Swnj 		    inp->inp_fport == fport &&
1234951Swnj 		    inp->inp_laddr.s_addr == laddr.s_addr &&
1244905Swnj 		    inp->inp_lport == lport)
1254905Swnj 			return (inp);
1264907Swnj 	for (inp = head->inp_next; inp != head; inp = inp->inp_next)
1274951Swnj 		if ((inp->inp_faddr.s_addr == faddr.s_addr ||
1284951Swnj 		     inp->inp_faddr.s_addr == 0) &&
1294905Swnj 		    (inp->inp_fport == fport || inp->inp_fport == 0) &&
1304951Swnj 		     inp->inp_laddr.s_addr == laddr.s_addr &&
1314905Swnj 		    (inp->inp_lport == lport || inp->inp_lport == 0))
1324905Swnj 			return (inp);
1334905Swnj 	return (0);
1344905Swnj }
135