1*14123Ssam /* in_pcb.c 4.41 83/07/25 */ 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); 13510141Ssam if (inp->inp_laddr.s_addr == INADDR_ANY) 1366338Ssam inp->inp_laddr = ifaddr->sin_addr; 1374951Swnj inp->inp_faddr = sin->sin_addr; 1384951Swnj inp->inp_fport = sin->sin_port; 1394923Swnj return (0); 1404923Swnj } 1414923Swnj 1425161Swnj in_pcbdisconnect(inp) 1434905Swnj struct inpcb *inp; 1444905Swnj { 1455161Swnj 14610141Ssam inp->inp_faddr.s_addr = INADDR_ANY; 1476028Sroot inp->inp_fport = 0; 1487506Sroot if (inp->inp_socket->so_state & SS_NOFDREF) 1495161Swnj in_pcbdetach(inp); 1505161Swnj } 1515161Swnj 1525161Swnj in_pcbdetach(inp) 1535161Swnj struct inpcb *inp; 1545161Swnj { 1554905Swnj struct socket *so = inp->inp_socket; 1564905Swnj 1575009Swnj so->so_pcb = 0; 1585009Swnj sofree(so); 1596350Ssam if (inp->inp_route.ro_rt) 1606367Ssam rtfree(inp->inp_route.ro_rt); 1614983Swnj remque(inp); 1624907Swnj (void) m_free(dtom(inp)); 1634905Swnj } 1644905Swnj 1658270Sroot in_setsockaddr(inp, nam) 1666509Ssam register struct inpcb *inp; 1678270Sroot struct mbuf *nam; 1686509Ssam { 1698270Sroot register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); 1708270Sroot 1718270Sroot nam->m_len = sizeof (*sin); 1728270Sroot sin = mtod(nam, struct sockaddr_in *); 1736509Ssam bzero((caddr_t)sin, sizeof (*sin)); 1746509Ssam sin->sin_family = AF_INET; 1756509Ssam sin->sin_port = inp->inp_lport; 1766509Ssam sin->sin_addr = inp->inp_laddr; 1776509Ssam } 1786509Ssam 179*14123Ssam in_setpeeraddr(inp, nam) 180*14123Ssam register struct inpcb *inp; 181*14123Ssam struct mbuf *nam; 182*14123Ssam { 183*14123Ssam register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); 184*14123Ssam 185*14123Ssam nam->m_len = sizeof (*sin); 186*14123Ssam sin = mtod(nam, struct sockaddr_in *); 187*14123Ssam bzero((caddr_t)sin, sizeof (*sin)); 188*14123Ssam sin->sin_family = AF_INET; 189*14123Ssam sin->sin_port = inp->inp_fport; 190*14123Ssam sin->sin_addr = inp->inp_faddr; 191*14123Ssam } 192*14123Ssam 1935161Swnj /* 1946583Ssam * Pass an error to all internet connections 1956583Ssam * associated with address sin. Call the 1966583Ssam * protocol specific routine to clean up the 1976583Ssam * mess afterwards. 1986583Ssam */ 1996583Ssam in_pcbnotify(head, dst, errno, abort) 2006583Ssam struct inpcb *head; 2016583Ssam register struct in_addr *dst; 2026583Ssam int errno, (*abort)(); 2036583Ssam { 2046583Ssam register struct inpcb *inp, *oinp; 2056583Ssam int s = splimp(); 2066583Ssam 2076583Ssam for (inp = head->inp_next; inp != head;) { 2086583Ssam if (inp->inp_faddr.s_addr != dst->s_addr) { 2096583Ssam next: 2106583Ssam inp = inp->inp_next; 2116583Ssam continue; 2126583Ssam } 2136583Ssam if (inp->inp_socket == 0) 2146583Ssam goto next; 2156583Ssam inp->inp_socket->so_error = errno; 2166583Ssam oinp = inp; 2176583Ssam inp = inp->inp_next; 2186583Ssam (*abort)(oinp); 2196583Ssam } 2206583Ssam splx(s); 2216583Ssam } 2226583Ssam 2234907Swnj struct inpcb * 2246028Sroot in_pcblookup(head, faddr, fport, laddr, lport, flags) 2254905Swnj struct inpcb *head; 2264951Swnj struct in_addr faddr, laddr; 2274905Swnj u_short fport, lport; 2286028Sroot int flags; 2294905Swnj { 2305994Swnj register struct inpcb *inp, *match = 0; 2315994Swnj int matchwild = 3, wildcard; 2324905Swnj 2335161Swnj for (inp = head->inp_next; inp != head; inp = inp->inp_next) { 2345994Swnj if (inp->inp_lport != lport) 2355161Swnj continue; 2365994Swnj wildcard = 0; 23710141Ssam if (inp->inp_laddr.s_addr != INADDR_ANY) { 23810141Ssam if (laddr.s_addr == INADDR_ANY) 2396116Swnj wildcard++; 2406116Swnj else if (inp->inp_laddr.s_addr != laddr.s_addr) 2415994Swnj continue; 2425994Swnj } else { 24310141Ssam if (laddr.s_addr != INADDR_ANY) 2445994Swnj wildcard++; 2455994Swnj } 24610141Ssam if (inp->inp_faddr.s_addr != INADDR_ANY) { 24710141Ssam if (faddr.s_addr == INADDR_ANY) 2486116Swnj wildcard++; 2496116Swnj else if (inp->inp_faddr.s_addr != faddr.s_addr || 2506028Sroot inp->inp_fport != fport) 2515994Swnj continue; 2525994Swnj } else { 25310141Ssam if (faddr.s_addr != INADDR_ANY) 2545994Swnj wildcard++; 2555994Swnj } 2566028Sroot if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0) 2575994Swnj continue; 2585994Swnj if (wildcard < matchwild) { 2595161Swnj match = inp; 2605994Swnj matchwild = wildcard; 2615994Swnj if (matchwild == 0) 2625994Swnj break; 2635161Swnj } 2645161Swnj } 2655161Swnj return (match); 2664905Swnj } 267