1*9639Ssam /* in_pcb.c 4.37 82/12/14 */ 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_pcballoc(so, head) 207506Sroot struct socket *so; 217506Sroot struct inpcb *head; 227506Sroot { 237506Sroot struct mbuf *m; 247506Sroot register struct inpcb *inp; 257506Sroot 26*9639Ssam m = m_getclr(M_DONTWAIT, MT_PCB); 277506Sroot if (m == 0) 287506Sroot return (ENOBUFS); 297506Sroot inp = mtod(m, struct inpcb *); 307506Sroot inp->inp_head = head; 317506Sroot inp->inp_socket = so; 327506Sroot insque(inp, head); 337506Sroot so->so_pcb = (caddr_t)inp; 347506Sroot return (0); 357506Sroot } 367506Sroot 378270Sroot in_pcbbind(inp, nam) 387506Sroot register struct inpcb *inp; 398270Sroot struct mbuf *nam; 407506Sroot { 417506Sroot register struct socket *so = inp->inp_socket; 427506Sroot register struct inpcb *head = inp->inp_head; 438270Sroot register struct sockaddr_in *sin; 447506Sroot u_short lport = 0; 457506Sroot 467506Sroot if (ifnet == 0) 477506Sroot return (EADDRNOTAVAIL); 488270Sroot if (inp->inp_lport || inp->inp_laddr.s_addr) 498270Sroot return (EINVAL); 508270Sroot if (nam == 0) 518270Sroot goto noname; 528270Sroot sin = mtod(nam, struct sockaddr_in *); 538270Sroot if (nam->m_len != sizeof (*sin)) 548270Sroot return (EINVAL); 558270Sroot if (sin->sin_addr.s_addr) { 568270Sroot int tport = sin->sin_port; 577506Sroot 588270Sroot sin->sin_port = 0; /* yech... */ 598270Sroot if (if_ifwithaddr((struct sockaddr *)sin) == 0) 608270Sroot return (EADDRNOTAVAIL); 618270Sroot sin->sin_port = tport; 627506Sroot } 638270Sroot lport = sin->sin_port; 648270Sroot if (lport) { 658937Sroot u_short aport = htons(lport); 668270Sroot int wild = 0; 677506Sroot 688270Sroot /* GROSS */ 698270Sroot if (aport < IPPORT_RESERVED && u.u_uid != 0) 708270Sroot return (EACCES); 718270Sroot if ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0) 728270Sroot wild = INPLOOKUP_WILDCARD; 738270Sroot if (in_pcblookup(head, 748270Sroot zeroin_addr, 0, sin->sin_addr, lport, wild)) 758270Sroot return (EADDRINUSE); 764951Swnj } 778270Sroot inp->inp_laddr = sin->sin_addr; 788270Sroot noname: 795172Swnj if (lport == 0) 805172Swnj do { 815994Swnj if (head->inp_lport++ < IPPORT_RESERVED) 825994Swnj head->inp_lport = IPPORT_RESERVED; 835172Swnj lport = htons(head->inp_lport); 845994Swnj } while (in_pcblookup(head, 855994Swnj zeroin_addr, 0, inp->inp_laddr, lport, 0)); 865172Swnj inp->inp_lport = lport; 874951Swnj return (0); 884905Swnj } 894905Swnj 906116Swnj /* 916116Swnj * Connect from a socket to a specified address. 926116Swnj * Both address and port must be specified in argument sin. 936116Swnj * If don't have a local address for this socket yet, 946116Swnj * then pick one. 956116Swnj */ 968270Sroot in_pcbconnect(inp, nam) 974951Swnj struct inpcb *inp; 988270Sroot struct mbuf *nam; 994923Swnj { 1005994Swnj struct ifnet *ifp; 1016338Ssam struct sockaddr_in *ifaddr; 1028270Sroot register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); 1034923Swnj 1048270Sroot if (nam->m_len != sizeof (*sin)) 1058270Sroot return (EINVAL); 1064951Swnj if (sin->sin_family != AF_INET) 1074951Swnj return (EAFNOSUPPORT); 1084951Swnj if (sin->sin_addr.s_addr == 0 || sin->sin_port == 0) 1094951Swnj return (EADDRNOTAVAIL); 1105994Swnj if (inp->inp_laddr.s_addr == 0) { 1117166Ssam ifp = if_ifonnetof(in_netof(sin->sin_addr)); 1126338Ssam if (ifp == 0) { 1136583Ssam /* 1146583Ssam * We should select the interface based on 1156583Ssam * the route to be used, but for udp this would 1166583Ssam * result in two calls to rtalloc for each packet 1176583Ssam * sent; hardly worthwhile... 1186583Ssam */ 1196338Ssam ifp = if_ifwithaf(AF_INET); 1206338Ssam if (ifp == 0) 1216583Ssam return (EADDRNOTAVAIL); 1226338Ssam } 1236338Ssam ifaddr = (struct sockaddr_in *)&ifp->if_addr; 1245994Swnj } 1255994Swnj if (in_pcblookup(inp->inp_head, 1266116Swnj sin->sin_addr, 1276116Swnj sin->sin_port, 1286338Ssam inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr, 1296116Swnj inp->inp_lport, 1306116Swnj 0)) 1315172Swnj return (EADDRINUSE); 1326509Ssam if (inp->inp_laddr.s_addr == 0) 1336338Ssam inp->inp_laddr = ifaddr->sin_addr; 1344951Swnj inp->inp_faddr = sin->sin_addr; 1354951Swnj inp->inp_fport = sin->sin_port; 1364923Swnj return (0); 1374923Swnj } 1384923Swnj 1395161Swnj in_pcbdisconnect(inp) 1404905Swnj struct inpcb *inp; 1414905Swnj { 1425161Swnj 1435161Swnj inp->inp_faddr.s_addr = 0; 1446028Sroot inp->inp_fport = 0; 1457506Sroot if (inp->inp_socket->so_state & SS_NOFDREF) 1465161Swnj in_pcbdetach(inp); 1475161Swnj } 1485161Swnj 1495161Swnj in_pcbdetach(inp) 1505161Swnj struct inpcb *inp; 1515161Swnj { 1524905Swnj struct socket *so = inp->inp_socket; 1534905Swnj 1545009Swnj so->so_pcb = 0; 1555009Swnj sofree(so); 1566350Ssam if (inp->inp_route.ro_rt) 1576367Ssam rtfree(inp->inp_route.ro_rt); 1584983Swnj remque(inp); 1594907Swnj (void) m_free(dtom(inp)); 1604905Swnj } 1614905Swnj 1628270Sroot in_setsockaddr(inp, nam) 1636509Ssam register struct inpcb *inp; 1648270Sroot struct mbuf *nam; 1656509Ssam { 1668270Sroot register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); 1678270Sroot 1688270Sroot nam->m_len = sizeof (*sin); 1698270Sroot sin = mtod(nam, struct sockaddr_in *); 1706509Ssam bzero((caddr_t)sin, sizeof (*sin)); 1716509Ssam sin->sin_family = AF_INET; 1726509Ssam sin->sin_port = inp->inp_lport; 1736509Ssam sin->sin_addr = inp->inp_laddr; 1746509Ssam } 1756509Ssam 1765161Swnj /* 1776583Ssam * Pass an error to all internet connections 1786583Ssam * associated with address sin. Call the 1796583Ssam * protocol specific routine to clean up the 1806583Ssam * mess afterwards. 1816583Ssam */ 1826583Ssam in_pcbnotify(head, dst, errno, abort) 1836583Ssam struct inpcb *head; 1846583Ssam register struct in_addr *dst; 1856583Ssam int errno, (*abort)(); 1866583Ssam { 1876583Ssam register struct inpcb *inp, *oinp; 1886583Ssam int s = splimp(); 1896583Ssam 1906583Ssam for (inp = head->inp_next; inp != head;) { 1916583Ssam if (inp->inp_faddr.s_addr != dst->s_addr) { 1926583Ssam next: 1936583Ssam inp = inp->inp_next; 1946583Ssam continue; 1956583Ssam } 1966583Ssam if (inp->inp_socket == 0) 1976583Ssam goto next; 1986583Ssam inp->inp_socket->so_error = errno; 1996583Ssam oinp = inp; 2006583Ssam inp = inp->inp_next; 2016583Ssam (*abort)(oinp); 2026583Ssam } 2036583Ssam splx(s); 2046583Ssam } 2056583Ssam 2064907Swnj struct inpcb * 2076028Sroot in_pcblookup(head, faddr, fport, laddr, lport, flags) 2084905Swnj struct inpcb *head; 2094951Swnj struct in_addr faddr, laddr; 2104905Swnj u_short fport, lport; 2116028Sroot int flags; 2124905Swnj { 2135994Swnj register struct inpcb *inp, *match = 0; 2145994Swnj int matchwild = 3, wildcard; 2154905Swnj 2165161Swnj for (inp = head->inp_next; inp != head; inp = inp->inp_next) { 2175994Swnj if (inp->inp_lport != lport) 2185161Swnj continue; 2195994Swnj wildcard = 0; 2205994Swnj if (inp->inp_laddr.s_addr != 0) { 2216116Swnj if (laddr.s_addr == 0) 2226116Swnj wildcard++; 2236116Swnj else if (inp->inp_laddr.s_addr != laddr.s_addr) 2245994Swnj continue; 2255994Swnj } else { 2265994Swnj if (laddr.s_addr != 0) 2275994Swnj wildcard++; 2285994Swnj } 2295994Swnj if (inp->inp_faddr.s_addr != 0) { 2306116Swnj if (faddr.s_addr == 0) 2316116Swnj wildcard++; 2326116Swnj else if (inp->inp_faddr.s_addr != faddr.s_addr || 2336028Sroot inp->inp_fport != fport) 2345994Swnj continue; 2355994Swnj } else { 2365994Swnj if (faddr.s_addr != 0) 2375994Swnj wildcard++; 2385994Swnj } 2396028Sroot if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0) 2405994Swnj continue; 2415994Swnj if (wildcard < matchwild) { 2425161Swnj match = inp; 2435994Swnj matchwild = wildcard; 2445994Swnj if (matchwild == 0) 2455994Swnj break; 2465161Swnj } 2475161Swnj } 2485161Swnj return (match); 2494905Swnj } 250