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