1*8937Sroot /* in_pcb.c 4.35 82/10/30 */ 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" 108397Swnj #include "../netinet/in.h" 118397Swnj #include "../netinet/in_systm.h" 124951Swnj #include "../net/if.h" 136350Ssam #include "../net/route.h" 148397Swnj #include "../netinet/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 538270Sroot in_pcbbind(inp, nam) 547506Sroot register struct inpcb *inp; 558270Sroot struct mbuf *nam; 567506Sroot { 577506Sroot register struct socket *so = inp->inp_socket; 587506Sroot register struct inpcb *head = inp->inp_head; 598270Sroot register struct sockaddr_in *sin; 607506Sroot u_short lport = 0; 617506Sroot 627506Sroot if (ifnet == 0) 637506Sroot return (EADDRNOTAVAIL); 648270Sroot if (inp->inp_lport || inp->inp_laddr.s_addr) 658270Sroot return (EINVAL); 668270Sroot if (nam == 0) 678270Sroot goto noname; 688270Sroot sin = mtod(nam, struct sockaddr_in *); 698270Sroot if (nam->m_len != sizeof (*sin)) 708270Sroot return (EINVAL); 718270Sroot if (sin->sin_addr.s_addr) { 728270Sroot int tport = sin->sin_port; 737506Sroot 748270Sroot sin->sin_port = 0; /* yech... */ 758270Sroot if (if_ifwithaddr((struct sockaddr *)sin) == 0) 768270Sroot return (EADDRNOTAVAIL); 778270Sroot sin->sin_port = tport; 787506Sroot } 798270Sroot lport = sin->sin_port; 808270Sroot if (lport) { 81*8937Sroot u_short aport = htons(lport); 828270Sroot int wild = 0; 837506Sroot 848270Sroot /* GROSS */ 858270Sroot if (aport < IPPORT_RESERVED && u.u_uid != 0) 868270Sroot return (EACCES); 878270Sroot if ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0) 888270Sroot wild = INPLOOKUP_WILDCARD; 898270Sroot if (in_pcblookup(head, 908270Sroot zeroin_addr, 0, sin->sin_addr, lport, wild)) 918270Sroot return (EADDRINUSE); 924951Swnj } 938270Sroot inp->inp_laddr = sin->sin_addr; 948270Sroot noname: 955172Swnj if (lport == 0) 965172Swnj do { 975994Swnj if (head->inp_lport++ < IPPORT_RESERVED) 985994Swnj head->inp_lport = IPPORT_RESERVED; 995172Swnj lport = htons(head->inp_lport); 1005994Swnj } while (in_pcblookup(head, 1015994Swnj zeroin_addr, 0, inp->inp_laddr, lport, 0)); 1025172Swnj inp->inp_lport = lport; 1034951Swnj return (0); 1044905Swnj } 1054905Swnj 1066116Swnj /* 1076116Swnj * Connect from a socket to a specified address. 1086116Swnj * Both address and port must be specified in argument sin. 1096116Swnj * If don't have a local address for this socket yet, 1106116Swnj * then pick one. 1116116Swnj */ 1128270Sroot in_pcbconnect(inp, nam) 1134951Swnj struct inpcb *inp; 1148270Sroot struct mbuf *nam; 1154923Swnj { 1165994Swnj struct ifnet *ifp; 1176338Ssam struct sockaddr_in *ifaddr; 1188270Sroot register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); 1194923Swnj 1208270Sroot if (nam->m_len != sizeof (*sin)) 1218270Sroot return (EINVAL); 1224951Swnj if (sin->sin_family != AF_INET) 1234951Swnj return (EAFNOSUPPORT); 1244951Swnj if (sin->sin_addr.s_addr == 0 || sin->sin_port == 0) 1254951Swnj return (EADDRNOTAVAIL); 1265994Swnj if (inp->inp_laddr.s_addr == 0) { 1277166Ssam ifp = if_ifonnetof(in_netof(sin->sin_addr)); 1286338Ssam if (ifp == 0) { 1296583Ssam /* 1306583Ssam * We should select the interface based on 1316583Ssam * the route to be used, but for udp this would 1326583Ssam * result in two calls to rtalloc for each packet 1336583Ssam * sent; hardly worthwhile... 1346583Ssam */ 1356338Ssam ifp = if_ifwithaf(AF_INET); 1366338Ssam if (ifp == 0) 1376583Ssam return (EADDRNOTAVAIL); 1386338Ssam } 1396338Ssam ifaddr = (struct sockaddr_in *)&ifp->if_addr; 1405994Swnj } 1415994Swnj if (in_pcblookup(inp->inp_head, 1426116Swnj sin->sin_addr, 1436116Swnj sin->sin_port, 1446338Ssam inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr, 1456116Swnj inp->inp_lport, 1466116Swnj 0)) 1475172Swnj return (EADDRINUSE); 1486509Ssam if (inp->inp_laddr.s_addr == 0) 1496338Ssam inp->inp_laddr = ifaddr->sin_addr; 1504951Swnj inp->inp_faddr = sin->sin_addr; 1514951Swnj inp->inp_fport = sin->sin_port; 1524923Swnj return (0); 1534923Swnj } 1544923Swnj 1555161Swnj in_pcbdisconnect(inp) 1564905Swnj struct inpcb *inp; 1574905Swnj { 1585161Swnj 1595161Swnj inp->inp_faddr.s_addr = 0; 1606028Sroot inp->inp_fport = 0; 1617506Sroot if (inp->inp_socket->so_state & SS_NOFDREF) 1625161Swnj in_pcbdetach(inp); 1635161Swnj } 1645161Swnj 1655161Swnj in_pcbdetach(inp) 1665161Swnj struct inpcb *inp; 1675161Swnj { 1684905Swnj struct socket *so = inp->inp_socket; 1694905Swnj 1705009Swnj so->so_pcb = 0; 1715009Swnj sofree(so); 1726350Ssam if (inp->inp_route.ro_rt) 1736367Ssam rtfree(inp->inp_route.ro_rt); 1744983Swnj remque(inp); 1754907Swnj (void) m_free(dtom(inp)); 1764905Swnj } 1774905Swnj 1788270Sroot in_setsockaddr(inp, nam) 1796509Ssam register struct inpcb *inp; 1808270Sroot struct mbuf *nam; 1816509Ssam { 1828270Sroot register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); 1838270Sroot 1848270Sroot nam->m_len = sizeof (*sin); 1858270Sroot sin = mtod(nam, struct sockaddr_in *); 1866509Ssam bzero((caddr_t)sin, sizeof (*sin)); 1876509Ssam sin->sin_family = AF_INET; 1886509Ssam sin->sin_port = inp->inp_lport; 1896509Ssam sin->sin_addr = inp->inp_laddr; 1906509Ssam } 1916509Ssam 1925161Swnj /* 1936583Ssam * Pass an error to all internet connections 1946583Ssam * associated with address sin. Call the 1956583Ssam * protocol specific routine to clean up the 1966583Ssam * mess afterwards. 1976583Ssam */ 1986583Ssam in_pcbnotify(head, dst, errno, abort) 1996583Ssam struct inpcb *head; 2006583Ssam register struct in_addr *dst; 2016583Ssam int errno, (*abort)(); 2026583Ssam { 2036583Ssam register struct inpcb *inp, *oinp; 2046583Ssam int s = splimp(); 2056583Ssam 2066583Ssam for (inp = head->inp_next; inp != head;) { 2076583Ssam if (inp->inp_faddr.s_addr != dst->s_addr) { 2086583Ssam next: 2096583Ssam inp = inp->inp_next; 2106583Ssam continue; 2116583Ssam } 2126583Ssam if (inp->inp_socket == 0) 2136583Ssam goto next; 2146583Ssam inp->inp_socket->so_error = errno; 2156583Ssam oinp = inp; 2166583Ssam inp = inp->inp_next; 2176583Ssam (*abort)(oinp); 2186583Ssam } 2196583Ssam splx(s); 2206583Ssam } 2216583Ssam 2224907Swnj struct inpcb * 2236028Sroot in_pcblookup(head, faddr, fport, laddr, lport, flags) 2244905Swnj struct inpcb *head; 2254951Swnj struct in_addr faddr, laddr; 2264905Swnj u_short fport, lport; 2276028Sroot int flags; 2284905Swnj { 2295994Swnj register struct inpcb *inp, *match = 0; 2305994Swnj int matchwild = 3, wildcard; 2314905Swnj 2325161Swnj for (inp = head->inp_next; inp != head; inp = inp->inp_next) { 2335994Swnj if (inp->inp_lport != lport) 2345161Swnj continue; 2355994Swnj wildcard = 0; 2365994Swnj if (inp->inp_laddr.s_addr != 0) { 2376116Swnj if (laddr.s_addr == 0) 2386116Swnj wildcard++; 2396116Swnj else if (inp->inp_laddr.s_addr != laddr.s_addr) 2405994Swnj continue; 2415994Swnj } else { 2425994Swnj if (laddr.s_addr != 0) 2435994Swnj wildcard++; 2445994Swnj } 2455994Swnj if (inp->inp_faddr.s_addr != 0) { 2466116Swnj if (faddr.s_addr == 0) 2476116Swnj wildcard++; 2486116Swnj else if (inp->inp_faddr.s_addr != faddr.s_addr || 2496028Sroot inp->inp_fport != fport) 2505994Swnj continue; 2515994Swnj } else { 2525994Swnj if (faddr.s_addr != 0) 2535994Swnj wildcard++; 2545994Swnj } 2556028Sroot if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0) 2565994Swnj continue; 2575994Swnj if (wildcard < matchwild) { 2585161Swnj match = inp; 2595994Swnj matchwild = wildcard; 2605994Swnj if (matchwild == 0) 2615994Swnj break; 2625161Swnj } 2635161Swnj } 2645161Swnj return (match); 2654905Swnj } 266