xref: /csrg-svn/sys/netinet/in_pcb.c (revision 8270)
1*8270Sroot /*	in_pcb.c	4.31	82/09/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"
105084Swnj #include "../net/in.h"
115084Swnj #include "../net/in_systm.h"
124951Swnj #include "../net/if.h"
136350Ssam #include "../net/route.h"
145084Swnj #include "../net/in_pcb.h"
156116Swnj #include "../h/protosw.h"
164905Swnj 
175240Sroot struct	in_addr zeroin_addr;
185161Swnj 
197506Sroot in_pcbreserve(so, sndcc, rcvcc)
207506Sroot 	struct socket *so;
217506Sroot 	int sndcc, rcvcc;
227506Sroot {
237506Sroot 
247506Sroot 	if (sbreserve(&so->so_snd, sndcc) == 0)
257506Sroot 		goto bad;
267506Sroot 	if (sbreserve(&so->so_rcv, rcvcc) == 0)
277506Sroot 		goto bad2;
287506Sroot 	return (0);
297506Sroot bad2:
307506Sroot 	sbrelease(&so->so_snd);
317506Sroot bad:
327506Sroot 	return (ENOBUFS);
337506Sroot }
347506Sroot 
357506Sroot in_pcballoc(so, head)
367506Sroot 	struct socket *so;
377506Sroot 	struct inpcb *head;
387506Sroot {
397506Sroot 	struct mbuf *m;
407506Sroot 	register struct inpcb *inp;
417506Sroot 
427506Sroot 	m = m_getclr(M_DONTWAIT);
437506Sroot 	if (m == 0)
447506Sroot 		return (ENOBUFS);
457506Sroot 	inp = mtod(m, struct inpcb *);
467506Sroot 	inp->inp_head = head;
477506Sroot 	inp->inp_socket = so;
487506Sroot 	insque(inp, head);
497506Sroot 	so->so_pcb = (caddr_t)inp;
507506Sroot 	return (0);
517506Sroot }
527506Sroot 
53*8270Sroot in_pcbbind(inp, nam)
547506Sroot 	register struct inpcb *inp;
55*8270Sroot 	struct mbuf *nam;
567506Sroot {
577506Sroot 	register struct socket *so = inp->inp_socket;
587506Sroot 	register struct inpcb *head = inp->inp_head;
59*8270Sroot 	register struct sockaddr_in *sin;
607506Sroot 	u_short lport = 0;
617506Sroot 
627506Sroot 	if (ifnet == 0)
637506Sroot 		return (EADDRNOTAVAIL);
64*8270Sroot 	if (inp->inp_lport || inp->inp_laddr.s_addr)
65*8270Sroot 		return (EINVAL);
66*8270Sroot 	if (nam == 0)
67*8270Sroot 		goto noname;
68*8270Sroot 	sin = mtod(nam, struct sockaddr_in *);
69*8270Sroot 	if (nam->m_len != sizeof (*sin))
70*8270Sroot 		return (EINVAL);
71*8270Sroot 	if (sin->sin_addr.s_addr) {
72*8270Sroot 		int tport = sin->sin_port;
737506Sroot 
74*8270Sroot 		sin->sin_port = 0;		/* yech... */
75*8270Sroot 		if (if_ifwithaddr((struct sockaddr *)sin) == 0)
76*8270Sroot 			return (EADDRNOTAVAIL);
77*8270Sroot 		sin->sin_port = tport;
787506Sroot 	}
79*8270Sroot 	lport = sin->sin_port;
80*8270Sroot 	if (lport) {
81*8270Sroot 		u_short aport = lport;
82*8270Sroot 		int wild = 0;
837506Sroot 
845994Swnj #if vax
85*8270Sroot 		aport = htons(aport);
865994Swnj #endif
87*8270Sroot 		/* GROSS */
88*8270Sroot 		if (aport < IPPORT_RESERVED && u.u_uid != 0)
89*8270Sroot 			return (EACCES);
90*8270Sroot 		if ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0)
91*8270Sroot 			wild = INPLOOKUP_WILDCARD;
92*8270Sroot 		if (in_pcblookup(head,
93*8270Sroot 		    zeroin_addr, 0, sin->sin_addr, lport, wild))
94*8270Sroot 			return (EADDRINUSE);
954951Swnj 	}
96*8270Sroot 	inp->inp_laddr = sin->sin_addr;
97*8270Sroot noname:
985172Swnj 	if (lport == 0)
995172Swnj 		do {
1005994Swnj 			if (head->inp_lport++ < IPPORT_RESERVED)
1015994Swnj 				head->inp_lport = IPPORT_RESERVED;
1025172Swnj 			lport = htons(head->inp_lport);
1035994Swnj 		} while (in_pcblookup(head,
1045994Swnj 			    zeroin_addr, 0, inp->inp_laddr, lport, 0));
1055172Swnj 	inp->inp_lport = lport;
1064951Swnj 	return (0);
1074905Swnj }
1084905Swnj 
1096116Swnj /*
1106116Swnj  * Connect from a socket to a specified address.
1116116Swnj  * Both address and port must be specified in argument sin.
1126116Swnj  * If don't have a local address for this socket yet,
1136116Swnj  * then pick one.
1146116Swnj  */
115*8270Sroot in_pcbconnect(inp, nam)
1164951Swnj 	struct inpcb *inp;
117*8270Sroot 	struct mbuf *nam;
1184923Swnj {
1195994Swnj 	struct ifnet *ifp;
1206338Ssam 	struct sockaddr_in *ifaddr;
121*8270Sroot 	register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
1224923Swnj 
123*8270Sroot 	if (nam->m_len != sizeof (*sin))
124*8270Sroot 		return (EINVAL);
1254951Swnj 	if (sin->sin_family != AF_INET)
1264951Swnj 		return (EAFNOSUPPORT);
1274951Swnj 	if (sin->sin_addr.s_addr == 0 || sin->sin_port == 0)
1284951Swnj 		return (EADDRNOTAVAIL);
1295994Swnj 	if (inp->inp_laddr.s_addr == 0) {
1307166Ssam 		ifp = if_ifonnetof(in_netof(sin->sin_addr));
1316338Ssam 		if (ifp == 0) {
1326583Ssam 			/*
1336583Ssam 			 * We should select the interface based on
1346583Ssam 			 * the route to be used, but for udp this would
1356583Ssam 			 * result in two calls to rtalloc for each packet
1366583Ssam 			 * sent; hardly worthwhile...
1376583Ssam 			 */
1386338Ssam 			ifp = if_ifwithaf(AF_INET);
1396338Ssam 			if (ifp == 0)
1406583Ssam 				return (EADDRNOTAVAIL);
1416338Ssam 		}
1426338Ssam 		ifaddr = (struct sockaddr_in *)&ifp->if_addr;
1435994Swnj 	}
1445994Swnj 	if (in_pcblookup(inp->inp_head,
1456116Swnj 	    sin->sin_addr,
1466116Swnj 	    sin->sin_port,
1476338Ssam 	    inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr,
1486116Swnj 	    inp->inp_lport,
1496116Swnj 	    0))
1505172Swnj 		return (EADDRINUSE);
1516509Ssam 	if (inp->inp_laddr.s_addr == 0)
1526338Ssam 		inp->inp_laddr = ifaddr->sin_addr;
1534951Swnj 	inp->inp_faddr = sin->sin_addr;
1544951Swnj 	inp->inp_fport = sin->sin_port;
1554923Swnj 	return (0);
1564923Swnj }
1574923Swnj 
1585161Swnj in_pcbdisconnect(inp)
1594905Swnj 	struct inpcb *inp;
1604905Swnj {
1615161Swnj 
1625161Swnj 	inp->inp_faddr.s_addr = 0;
1636028Sroot 	inp->inp_fport = 0;
1647506Sroot 	if (inp->inp_socket->so_state & SS_NOFDREF)
1655161Swnj 		in_pcbdetach(inp);
1665161Swnj }
1675161Swnj 
1685161Swnj in_pcbdetach(inp)
1695161Swnj 	struct inpcb *inp;
1705161Swnj {
1714905Swnj 	struct socket *so = inp->inp_socket;
1724905Swnj 
1735009Swnj 	so->so_pcb = 0;
1745009Swnj 	sofree(so);
1756350Ssam 	if (inp->inp_route.ro_rt)
1766367Ssam 		rtfree(inp->inp_route.ro_rt);
1774983Swnj 	remque(inp);
1784907Swnj 	(void) m_free(dtom(inp));
1794905Swnj }
1804905Swnj 
181*8270Sroot in_setsockaddr(inp, nam)
1826509Ssam 	register struct inpcb *inp;
183*8270Sroot 	struct mbuf *nam;
1846509Ssam {
185*8270Sroot 	register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
186*8270Sroot 
187*8270Sroot 	nam->m_len = sizeof (*sin);
188*8270Sroot 	sin = mtod(nam, struct sockaddr_in *);
1896509Ssam 	bzero((caddr_t)sin, sizeof (*sin));
1906509Ssam 	sin->sin_family = AF_INET;
1916509Ssam 	sin->sin_port = inp->inp_lport;
1926509Ssam 	sin->sin_addr = inp->inp_laddr;
1936509Ssam }
1946509Ssam 
1955161Swnj /*
1966583Ssam  * Pass an error to all internet connections
1976583Ssam  * associated with address sin.  Call the
1986583Ssam  * protocol specific routine to clean up the
1996583Ssam  * mess afterwards.
2006583Ssam  */
2016583Ssam in_pcbnotify(head, dst, errno, abort)
2026583Ssam 	struct inpcb *head;
2036583Ssam 	register struct in_addr *dst;
2046583Ssam 	int errno, (*abort)();
2056583Ssam {
2066583Ssam 	register struct inpcb *inp, *oinp;
2076583Ssam 	int s = splimp();
2086583Ssam 
2096583Ssam 	for (inp = head->inp_next; inp != head;) {
2106583Ssam 		if (inp->inp_faddr.s_addr != dst->s_addr) {
2116583Ssam 	next:
2126583Ssam 			inp = inp->inp_next;
2136583Ssam 			continue;
2146583Ssam 		}
2156583Ssam 		if (inp->inp_socket == 0)
2166583Ssam 			goto next;
2176583Ssam 		inp->inp_socket->so_error = errno;
2186583Ssam 		oinp = inp;
2196583Ssam 		inp = inp->inp_next;
2206583Ssam 		(*abort)(oinp);
2216583Ssam 	}
2226583Ssam 	splx(s);
2236583Ssam }
2246583Ssam 
2254907Swnj struct inpcb *
2266028Sroot in_pcblookup(head, faddr, fport, laddr, lport, flags)
2274905Swnj 	struct inpcb *head;
2284951Swnj 	struct in_addr faddr, laddr;
2294905Swnj 	u_short fport, lport;
2306028Sroot 	int flags;
2314905Swnj {
2325994Swnj 	register struct inpcb *inp, *match = 0;
2335994Swnj 	int matchwild = 3, wildcard;
2344905Swnj 
2355161Swnj 	for (inp = head->inp_next; inp != head; inp = inp->inp_next) {
2365994Swnj 		if (inp->inp_lport != lport)
2375161Swnj 			continue;
2385994Swnj 		wildcard = 0;
2395994Swnj 		if (inp->inp_laddr.s_addr != 0) {
2406116Swnj 			if (laddr.s_addr == 0)
2416116Swnj 				wildcard++;
2426116Swnj 			else if (inp->inp_laddr.s_addr != laddr.s_addr)
2435994Swnj 				continue;
2445994Swnj 		} else {
2455994Swnj 			if (laddr.s_addr != 0)
2465994Swnj 				wildcard++;
2475994Swnj 		}
2485994Swnj 		if (inp->inp_faddr.s_addr != 0) {
2496116Swnj 			if (faddr.s_addr == 0)
2506116Swnj 				wildcard++;
2516116Swnj 			else if (inp->inp_faddr.s_addr != faddr.s_addr ||
2526028Sroot 			    inp->inp_fport != fport)
2535994Swnj 				continue;
2545994Swnj 		} else {
2555994Swnj 			if (faddr.s_addr != 0)
2565994Swnj 				wildcard++;
2575994Swnj 		}
2586028Sroot 		if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0)
2595994Swnj 			continue;
2605994Swnj 		if (wildcard < matchwild) {
2615161Swnj 			match = inp;
2625994Swnj 			matchwild = wildcard;
2635994Swnj 			if (matchwild == 0)
2645994Swnj 				break;
2655161Swnj 		}
2665161Swnj 	}
2675161Swnj 	return (match);
2684905Swnj }
269