1*17271Skarels /* in_pcb.c 6.3 84/10/19 */ 24905Swnj 317058Sbloom #include "param.h" 417058Sbloom #include "systm.h" 517058Sbloom #include "dir.h" 617058Sbloom #include "user.h" 717058Sbloom #include "mbuf.h" 817058Sbloom #include "socket.h" 917058Sbloom #include "socketvar.h" 1017058Sbloom #include "in.h" 1117058Sbloom #include "in_systm.h" 124951Swnj #include "../net/if.h" 136350Ssam #include "../net/route.h" 1417058Sbloom #include "in_pcb.h" 1517058Sbloom #include "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) { 116*17271Skarels register struct route *ro; 117*17271Skarels 118*17271Skarels /* 119*17271Skarels * If route is known or can be allocated now, 120*17271Skarels * our src addr is taken from the i/f, else punt. 1216583Ssam */ 122*17271Skarels ro = &inp->inp_route; 123*17271Skarels #define satosin(sa) ((struct sockaddr_in *)(sa)) 124*17271Skarels if (ro->ro_rt && 125*17271Skarels satosin(&ro->ro_dst)->sin_addr.s_addr != 126*17271Skarels sin->sin_addr.s_addr) { 127*17271Skarels RTFREE(ro->ro_rt); 128*17271Skarels ro->ro_rt = (struct rtentry *)0; 129*17271Skarels } 130*17271Skarels if ((ro->ro_rt == (struct rtentry *)0) || 131*17271Skarels (ifp = ro->ro_rt->rt_ifp) == (struct ifnet *)0) { 132*17271Skarels /* No route yet, so try to acquire one */ 133*17271Skarels ro->ro_dst.sa_family = AF_INET; 134*17271Skarels ((struct sockaddr_in *) &ro->ro_dst)->sin_addr = 135*17271Skarels sin->sin_addr; 136*17271Skarels rtalloc(ro); 137*17271Skarels if (ro->ro_rt == 0) 138*17271Skarels ifp = (struct ifnet *) 0; 139*17271Skarels else 140*17271Skarels ifp = ro->ro_rt->rt_ifp; 141*17271Skarels } 1426338Ssam if (ifp == 0) 143*17271Skarels ifp = if_ifwithaf(AF_INET); 144*17271Skarels if (ifp == 0) 1456583Ssam return (EADDRNOTAVAIL); 1466338Ssam } 1476338Ssam ifaddr = (struct sockaddr_in *)&ifp->if_addr; 1485994Swnj } 1495994Swnj if (in_pcblookup(inp->inp_head, 1506116Swnj sin->sin_addr, 1516116Swnj sin->sin_port, 1526338Ssam inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr, 1536116Swnj inp->inp_lport, 1546116Swnj 0)) 1555172Swnj return (EADDRINUSE); 15614146Ssam if (inp->inp_laddr.s_addr == INADDR_ANY) { 15714146Ssam if (inp->inp_lport == 0) 15814146Ssam in_pcbbind(inp, (struct mbuf *)0); 1596338Ssam inp->inp_laddr = ifaddr->sin_addr; 16014146Ssam } 1614951Swnj inp->inp_faddr = sin->sin_addr; 1624951Swnj inp->inp_fport = sin->sin_port; 1634923Swnj return (0); 1644923Swnj } 1654923Swnj 1665161Swnj in_pcbdisconnect(inp) 1674905Swnj struct inpcb *inp; 1684905Swnj { 1695161Swnj 17010141Ssam inp->inp_faddr.s_addr = INADDR_ANY; 1716028Sroot inp->inp_fport = 0; 1727506Sroot if (inp->inp_socket->so_state & SS_NOFDREF) 1735161Swnj in_pcbdetach(inp); 1745161Swnj } 1755161Swnj 1765161Swnj in_pcbdetach(inp) 1775161Swnj struct inpcb *inp; 1785161Swnj { 1794905Swnj struct socket *so = inp->inp_socket; 1804905Swnj 1815009Swnj so->so_pcb = 0; 1825009Swnj sofree(so); 1836350Ssam if (inp->inp_route.ro_rt) 1846367Ssam rtfree(inp->inp_route.ro_rt); 1854983Swnj remque(inp); 1864907Swnj (void) m_free(dtom(inp)); 1874905Swnj } 1884905Swnj 1898270Sroot in_setsockaddr(inp, nam) 1906509Ssam register struct inpcb *inp; 1918270Sroot struct mbuf *nam; 1926509Ssam { 1938270Sroot register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); 1948270Sroot 1958270Sroot nam->m_len = sizeof (*sin); 1968270Sroot sin = mtod(nam, struct sockaddr_in *); 1976509Ssam bzero((caddr_t)sin, sizeof (*sin)); 1986509Ssam sin->sin_family = AF_INET; 1996509Ssam sin->sin_port = inp->inp_lport; 2006509Ssam sin->sin_addr = inp->inp_laddr; 2016509Ssam } 2026509Ssam 20314123Ssam in_setpeeraddr(inp, nam) 20414123Ssam register struct inpcb *inp; 20514123Ssam struct mbuf *nam; 20614123Ssam { 20714123Ssam register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); 20814123Ssam 20914123Ssam nam->m_len = sizeof (*sin); 21014123Ssam sin = mtod(nam, struct sockaddr_in *); 21114123Ssam bzero((caddr_t)sin, sizeof (*sin)); 21214123Ssam sin->sin_family = AF_INET; 21314123Ssam sin->sin_port = inp->inp_fport; 21414123Ssam sin->sin_addr = inp->inp_faddr; 21514123Ssam } 21614123Ssam 2175161Swnj /* 2186583Ssam * Pass an error to all internet connections 2196583Ssam * associated with address sin. Call the 2206583Ssam * protocol specific routine to clean up the 2216583Ssam * mess afterwards. 2226583Ssam */ 2236583Ssam in_pcbnotify(head, dst, errno, abort) 2246583Ssam struct inpcb *head; 2256583Ssam register struct in_addr *dst; 2266583Ssam int errno, (*abort)(); 2276583Ssam { 2286583Ssam register struct inpcb *inp, *oinp; 2296583Ssam int s = splimp(); 2306583Ssam 2316583Ssam for (inp = head->inp_next; inp != head;) { 2326583Ssam if (inp->inp_faddr.s_addr != dst->s_addr) { 2336583Ssam next: 2346583Ssam inp = inp->inp_next; 2356583Ssam continue; 2366583Ssam } 2376583Ssam if (inp->inp_socket == 0) 2386583Ssam goto next; 2396583Ssam inp->inp_socket->so_error = errno; 2406583Ssam oinp = inp; 2416583Ssam inp = inp->inp_next; 2426583Ssam (*abort)(oinp); 2436583Ssam } 2446583Ssam splx(s); 2456583Ssam } 2466583Ssam 2474907Swnj struct inpcb * 2486028Sroot in_pcblookup(head, faddr, fport, laddr, lport, flags) 2494905Swnj struct inpcb *head; 2504951Swnj struct in_addr faddr, laddr; 2514905Swnj u_short fport, lport; 2526028Sroot int flags; 2534905Swnj { 2545994Swnj register struct inpcb *inp, *match = 0; 2555994Swnj int matchwild = 3, wildcard; 2564905Swnj 2575161Swnj for (inp = head->inp_next; inp != head; inp = inp->inp_next) { 2585994Swnj if (inp->inp_lport != lport) 2595161Swnj continue; 2605994Swnj wildcard = 0; 26110141Ssam if (inp->inp_laddr.s_addr != INADDR_ANY) { 26210141Ssam if (laddr.s_addr == INADDR_ANY) 2636116Swnj wildcard++; 2646116Swnj else if (inp->inp_laddr.s_addr != laddr.s_addr) 2655994Swnj continue; 2665994Swnj } else { 26710141Ssam if (laddr.s_addr != INADDR_ANY) 2685994Swnj wildcard++; 2695994Swnj } 27010141Ssam if (inp->inp_faddr.s_addr != INADDR_ANY) { 27110141Ssam if (faddr.s_addr == INADDR_ANY) 2726116Swnj wildcard++; 2736116Swnj else if (inp->inp_faddr.s_addr != faddr.s_addr || 2746028Sroot inp->inp_fport != fport) 2755994Swnj continue; 2765994Swnj } else { 27710141Ssam if (faddr.s_addr != INADDR_ANY) 2785994Swnj wildcard++; 2795994Swnj } 2806028Sroot if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0) 2815994Swnj continue; 2825994Swnj if (wildcard < matchwild) { 2835161Swnj match = inp; 2845994Swnj matchwild = wildcard; 2855994Swnj if (matchwild == 0) 2865994Swnj break; 2875161Swnj } 2885161Swnj } 2895161Swnj return (match); 2904905Swnj } 291