1*14146Ssam /* in_pcb.c 4.42 83/07/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" 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 269639Ssam m = m_getclr(M_DONTWAIT, MT_PCB); 2710141Ssam if (m == NULL) 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); 4810141Ssam if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY) 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); 5510141Ssam if (sin->sin_addr.s_addr != INADDR_ANY) { 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); 7110598Ssam /* even GROSSER, but this is the Internet */ 7210598Ssam if ((so->so_options & SO_REUSEADDR) == 0 && 7310598Ssam ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 || 7410598Ssam (so->so_options & SO_ACCEPTCONN) == 0)) 758270Sroot wild = INPLOOKUP_WILDCARD; 768270Sroot if (in_pcblookup(head, 778270Sroot zeroin_addr, 0, sin->sin_addr, lport, wild)) 788270Sroot return (EADDRINUSE); 794951Swnj } 808270Sroot inp->inp_laddr = sin->sin_addr; 818270Sroot noname: 825172Swnj if (lport == 0) 835172Swnj do { 845994Swnj if (head->inp_lport++ < IPPORT_RESERVED) 855994Swnj head->inp_lport = IPPORT_RESERVED; 865172Swnj lport = htons(head->inp_lport); 875994Swnj } while (in_pcblookup(head, 885994Swnj zeroin_addr, 0, inp->inp_laddr, lport, 0)); 895172Swnj inp->inp_lport = lport; 904951Swnj return (0); 914905Swnj } 924905Swnj 936116Swnj /* 946116Swnj * Connect from a socket to a specified address. 956116Swnj * Both address and port must be specified in argument sin. 966116Swnj * If don't have a local address for this socket yet, 976116Swnj * then pick one. 986116Swnj */ 998270Sroot in_pcbconnect(inp, nam) 1004951Swnj struct inpcb *inp; 1018270Sroot struct mbuf *nam; 1024923Swnj { 1035994Swnj struct ifnet *ifp; 1046338Ssam struct sockaddr_in *ifaddr; 1058270Sroot register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); 1064923Swnj 1078270Sroot if (nam->m_len != sizeof (*sin)) 1088270Sroot return (EINVAL); 1094951Swnj if (sin->sin_family != AF_INET) 1104951Swnj return (EAFNOSUPPORT); 11110141Ssam if (sin->sin_addr.s_addr == INADDR_ANY || sin->sin_port == 0) 1124951Swnj return (EADDRNOTAVAIL); 11310141Ssam if (inp->inp_laddr.s_addr == INADDR_ANY) { 1147166Ssam ifp = if_ifonnetof(in_netof(sin->sin_addr)); 1156338Ssam if (ifp == 0) { 1166583Ssam /* 1176583Ssam * We should select the interface based on 1186583Ssam * the route to be used, but for udp this would 1196583Ssam * result in two calls to rtalloc for each packet 1206583Ssam * sent; hardly worthwhile... 1216583Ssam */ 1226338Ssam ifp = if_ifwithaf(AF_INET); 1236338Ssam if (ifp == 0) 1246583Ssam return (EADDRNOTAVAIL); 1256338Ssam } 1266338Ssam ifaddr = (struct sockaddr_in *)&ifp->if_addr; 1275994Swnj } 1285994Swnj if (in_pcblookup(inp->inp_head, 1296116Swnj sin->sin_addr, 1306116Swnj sin->sin_port, 1316338Ssam inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr, 1326116Swnj inp->inp_lport, 1336116Swnj 0)) 1345172Swnj return (EADDRINUSE); 135*14146Ssam if (inp->inp_laddr.s_addr == INADDR_ANY) { 136*14146Ssam if (inp->inp_lport == 0) 137*14146Ssam in_pcbbind(inp, (struct mbuf *)0); 1386338Ssam inp->inp_laddr = ifaddr->sin_addr; 139*14146Ssam } 1404951Swnj inp->inp_faddr = sin->sin_addr; 1414951Swnj inp->inp_fport = sin->sin_port; 1424923Swnj return (0); 1434923Swnj } 1444923Swnj 1455161Swnj in_pcbdisconnect(inp) 1464905Swnj struct inpcb *inp; 1474905Swnj { 1485161Swnj 14910141Ssam inp->inp_faddr.s_addr = INADDR_ANY; 1506028Sroot inp->inp_fport = 0; 1517506Sroot if (inp->inp_socket->so_state & SS_NOFDREF) 1525161Swnj in_pcbdetach(inp); 1535161Swnj } 1545161Swnj 1555161Swnj in_pcbdetach(inp) 1565161Swnj struct inpcb *inp; 1575161Swnj { 1584905Swnj struct socket *so = inp->inp_socket; 1594905Swnj 1605009Swnj so->so_pcb = 0; 1615009Swnj sofree(so); 1626350Ssam if (inp->inp_route.ro_rt) 1636367Ssam rtfree(inp->inp_route.ro_rt); 1644983Swnj remque(inp); 1654907Swnj (void) m_free(dtom(inp)); 1664905Swnj } 1674905Swnj 1688270Sroot in_setsockaddr(inp, nam) 1696509Ssam register struct inpcb *inp; 1708270Sroot struct mbuf *nam; 1716509Ssam { 1728270Sroot register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); 1738270Sroot 1748270Sroot nam->m_len = sizeof (*sin); 1758270Sroot sin = mtod(nam, struct sockaddr_in *); 1766509Ssam bzero((caddr_t)sin, sizeof (*sin)); 1776509Ssam sin->sin_family = AF_INET; 1786509Ssam sin->sin_port = inp->inp_lport; 1796509Ssam sin->sin_addr = inp->inp_laddr; 1806509Ssam } 1816509Ssam 18214123Ssam in_setpeeraddr(inp, nam) 18314123Ssam register struct inpcb *inp; 18414123Ssam struct mbuf *nam; 18514123Ssam { 18614123Ssam register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); 18714123Ssam 18814123Ssam nam->m_len = sizeof (*sin); 18914123Ssam sin = mtod(nam, struct sockaddr_in *); 19014123Ssam bzero((caddr_t)sin, sizeof (*sin)); 19114123Ssam sin->sin_family = AF_INET; 19214123Ssam sin->sin_port = inp->inp_fport; 19314123Ssam sin->sin_addr = inp->inp_faddr; 19414123Ssam } 19514123Ssam 1965161Swnj /* 1976583Ssam * Pass an error to all internet connections 1986583Ssam * associated with address sin. Call the 1996583Ssam * protocol specific routine to clean up the 2006583Ssam * mess afterwards. 2016583Ssam */ 2026583Ssam in_pcbnotify(head, dst, errno, abort) 2036583Ssam struct inpcb *head; 2046583Ssam register struct in_addr *dst; 2056583Ssam int errno, (*abort)(); 2066583Ssam { 2076583Ssam register struct inpcb *inp, *oinp; 2086583Ssam int s = splimp(); 2096583Ssam 2106583Ssam for (inp = head->inp_next; inp != head;) { 2116583Ssam if (inp->inp_faddr.s_addr != dst->s_addr) { 2126583Ssam next: 2136583Ssam inp = inp->inp_next; 2146583Ssam continue; 2156583Ssam } 2166583Ssam if (inp->inp_socket == 0) 2176583Ssam goto next; 2186583Ssam inp->inp_socket->so_error = errno; 2196583Ssam oinp = inp; 2206583Ssam inp = inp->inp_next; 2216583Ssam (*abort)(oinp); 2226583Ssam } 2236583Ssam splx(s); 2246583Ssam } 2256583Ssam 2264907Swnj struct inpcb * 2276028Sroot in_pcblookup(head, faddr, fport, laddr, lport, flags) 2284905Swnj struct inpcb *head; 2294951Swnj struct in_addr faddr, laddr; 2304905Swnj u_short fport, lport; 2316028Sroot int flags; 2324905Swnj { 2335994Swnj register struct inpcb *inp, *match = 0; 2345994Swnj int matchwild = 3, wildcard; 2354905Swnj 2365161Swnj for (inp = head->inp_next; inp != head; inp = inp->inp_next) { 2375994Swnj if (inp->inp_lport != lport) 2385161Swnj continue; 2395994Swnj wildcard = 0; 24010141Ssam if (inp->inp_laddr.s_addr != INADDR_ANY) { 24110141Ssam if (laddr.s_addr == INADDR_ANY) 2426116Swnj wildcard++; 2436116Swnj else if (inp->inp_laddr.s_addr != laddr.s_addr) 2445994Swnj continue; 2455994Swnj } else { 24610141Ssam if (laddr.s_addr != INADDR_ANY) 2475994Swnj wildcard++; 2485994Swnj } 24910141Ssam if (inp->inp_faddr.s_addr != INADDR_ANY) { 25010141Ssam if (faddr.s_addr == INADDR_ANY) 2516116Swnj wildcard++; 2526116Swnj else if (inp->inp_faddr.s_addr != faddr.s_addr || 2536028Sroot inp->inp_fport != fport) 2545994Swnj continue; 2555994Swnj } else { 25610141Ssam if (faddr.s_addr != INADDR_ANY) 2575994Swnj wildcard++; 2585994Swnj } 2596028Sroot if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0) 2605994Swnj continue; 2615994Swnj if (wildcard < matchwild) { 2625161Swnj match = inp; 2635994Swnj matchwild = wildcard; 2645994Swnj if (matchwild == 0) 2655994Swnj break; 2665161Swnj } 2675161Swnj } 2685161Swnj return (match); 2694905Swnj } 270