1*18655Skarels /* in_pcb.c 6.7 85/04/18 */ 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" 1518374Skarels #include "in_var.h" 1617058Sbloom #include "protosw.h" 174905Swnj 185240Sroot struct in_addr zeroin_addr; 195161Swnj 207506Sroot in_pcballoc(so, head) 217506Sroot struct socket *so; 227506Sroot struct inpcb *head; 237506Sroot { 247506Sroot struct mbuf *m; 257506Sroot register struct inpcb *inp; 267506Sroot 279639Ssam m = m_getclr(M_DONTWAIT, MT_PCB); 2810141Ssam if (m == NULL) 297506Sroot return (ENOBUFS); 307506Sroot inp = mtod(m, struct inpcb *); 317506Sroot inp->inp_head = head; 327506Sroot inp->inp_socket = so; 337506Sroot insque(inp, head); 347506Sroot so->so_pcb = (caddr_t)inp; 357506Sroot return (0); 367506Sroot } 377506Sroot 388270Sroot in_pcbbind(inp, nam) 397506Sroot register struct inpcb *inp; 408270Sroot struct mbuf *nam; 417506Sroot { 427506Sroot register struct socket *so = inp->inp_socket; 437506Sroot register struct inpcb *head = inp->inp_head; 448270Sroot register struct sockaddr_in *sin; 457506Sroot u_short lport = 0; 467506Sroot 4718374Skarels if (in_ifaddr == 0) 487506Sroot return (EADDRNOTAVAIL); 4910141Ssam if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY) 508270Sroot return (EINVAL); 518270Sroot if (nam == 0) 528270Sroot goto noname; 538270Sroot sin = mtod(nam, struct sockaddr_in *); 548270Sroot if (nam->m_len != sizeof (*sin)) 558270Sroot return (EINVAL); 5610141Ssam if (sin->sin_addr.s_addr != INADDR_ANY) { 578270Sroot int tport = sin->sin_port; 587506Sroot 598270Sroot sin->sin_port = 0; /* yech... */ 6018374Skarels if (ifa_ifwithaddr((struct sockaddr *)sin) == 0) 618270Sroot return (EADDRNOTAVAIL); 628270Sroot sin->sin_port = tport; 637506Sroot } 648270Sroot lport = sin->sin_port; 658270Sroot if (lport) { 6617429Skarels u_short aport = ntohs(lport); 678270Sroot int wild = 0; 687506Sroot 698270Sroot /* GROSS */ 708270Sroot if (aport < IPPORT_RESERVED && u.u_uid != 0) 718270Sroot return (EACCES); 7210598Ssam /* even GROSSER, but this is the Internet */ 7310598Ssam if ((so->so_options & SO_REUSEADDR) == 0 && 7410598Ssam ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 || 7510598Ssam (so->so_options & SO_ACCEPTCONN) == 0)) 768270Sroot wild = INPLOOKUP_WILDCARD; 778270Sroot if (in_pcblookup(head, 788270Sroot zeroin_addr, 0, sin->sin_addr, lport, wild)) 798270Sroot return (EADDRINUSE); 804951Swnj } 818270Sroot inp->inp_laddr = sin->sin_addr; 828270Sroot noname: 835172Swnj if (lport == 0) 845172Swnj do { 855994Swnj if (head->inp_lport++ < IPPORT_RESERVED) 865994Swnj head->inp_lport = IPPORT_RESERVED; 875172Swnj lport = htons(head->inp_lport); 885994Swnj } while (in_pcblookup(head, 895994Swnj zeroin_addr, 0, inp->inp_laddr, lport, 0)); 905172Swnj inp->inp_lport = lport; 914951Swnj return (0); 924905Swnj } 934905Swnj 946116Swnj /* 956116Swnj * Connect from a socket to a specified address. 966116Swnj * Both address and port must be specified in argument sin. 976116Swnj * If don't have a local address for this socket yet, 986116Swnj * then pick one. 996116Swnj */ 1008270Sroot in_pcbconnect(inp, nam) 1014951Swnj struct inpcb *inp; 1028270Sroot struct mbuf *nam; 1034923Swnj { 10418374Skarels struct in_ifaddr *ia; 1056338Ssam struct sockaddr_in *ifaddr; 1068270Sroot register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); 1074923Swnj 1088270Sroot if (nam->m_len != sizeof (*sin)) 1098270Sroot return (EINVAL); 1104951Swnj if (sin->sin_family != AF_INET) 1114951Swnj return (EAFNOSUPPORT); 11218374Skarels if (sin->sin_port == 0) 1134951Swnj return (EADDRNOTAVAIL); 11418374Skarels if (in_ifaddr) { 115*18655Skarels /* 116*18655Skarels * If the destination address is INADDR_ANY, 117*18655Skarels * use the primary local address. 118*18655Skarels * If the supplied address is INADDR_BROADCAST, 119*18655Skarels * and the primary interface supports broadcast, 120*18655Skarels * choose the broadcast address for that interface. 121*18655Skarels */ 12218374Skarels #define satosin(sa) ((struct sockaddr_in *)(sa)) 12318374Skarels if (sin->sin_addr.s_addr == INADDR_ANY) 124*18655Skarels sin->sin_addr = IA_SIN(in_ifaddr)->sin_addr; 125*18655Skarels else if (sin->sin_addr.s_addr == INADDR_BROADCAST && 126*18655Skarels (in_ifaddr->ia_ifp->if_flags & IFF_BROADCAST)) 127*18655Skarels sin->sin_addr = satosin(&in_ifaddr->ia_broadaddr)->sin_addr; 12818374Skarels } 12910141Ssam if (inp->inp_laddr.s_addr == INADDR_ANY) { 130*18655Skarels ia = (struct in_ifaddr *)ifa_ifwithnet((struct sockaddr *)sin); 13118374Skarels if (ia == (struct in_ifaddr *)0) { 13217271Skarels register struct route *ro; 13318374Skarels struct ifnet *ifp; 13417271Skarels 13517271Skarels /* 13617271Skarels * If route is known or can be allocated now, 13717271Skarels * our src addr is taken from the i/f, else punt. 1386583Ssam */ 13917271Skarels ro = &inp->inp_route; 14017271Skarels if (ro->ro_rt && 14117271Skarels satosin(&ro->ro_dst)->sin_addr.s_addr != 14217271Skarels sin->sin_addr.s_addr) { 14317271Skarels RTFREE(ro->ro_rt); 14417271Skarels ro->ro_rt = (struct rtentry *)0; 14517271Skarels } 14617271Skarels if ((ro->ro_rt == (struct rtentry *)0) || 14717271Skarels (ifp = ro->ro_rt->rt_ifp) == (struct ifnet *)0) { 14817271Skarels /* No route yet, so try to acquire one */ 14917271Skarels ro->ro_dst.sa_family = AF_INET; 15017271Skarels ((struct sockaddr_in *) &ro->ro_dst)->sin_addr = 15117271Skarels sin->sin_addr; 15217271Skarels rtalloc(ro); 15317271Skarels if (ro->ro_rt == 0) 154*18655Skarels ifp = (struct ifnet *)0; 15517271Skarels else 156*18655Skarels ifp = ro->ro_rt->rt_ifp; 157*18655Skarels } 158*18655Skarels if (ifp) { 159*18655Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 16018374Skarels if (ia->ia_ifp == ifp) 161*18655Skarels break; 162*18655Skarels } else 163*18655Skarels ia = (struct in_ifaddr *)0; 16418374Skarels if (ia == 0) 16518374Skarels ia = in_ifaddr; 16618374Skarels if (ia == 0) 1676583Ssam return (EADDRNOTAVAIL); 1686338Ssam } 16918374Skarels ifaddr = (struct sockaddr_in *)&ia->ia_addr; 1705994Swnj } 1715994Swnj if (in_pcblookup(inp->inp_head, 1726116Swnj sin->sin_addr, 1736116Swnj sin->sin_port, 1746338Ssam inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr, 1756116Swnj inp->inp_lport, 1766116Swnj 0)) 1775172Swnj return (EADDRINUSE); 17814146Ssam if (inp->inp_laddr.s_addr == INADDR_ANY) { 17914146Ssam if (inp->inp_lport == 0) 18014146Ssam in_pcbbind(inp, (struct mbuf *)0); 1816338Ssam inp->inp_laddr = ifaddr->sin_addr; 18214146Ssam } 1834951Swnj inp->inp_faddr = sin->sin_addr; 1844951Swnj inp->inp_fport = sin->sin_port; 1854923Swnj return (0); 1864923Swnj } 1874923Swnj 1885161Swnj in_pcbdisconnect(inp) 1894905Swnj struct inpcb *inp; 1904905Swnj { 1915161Swnj 19210141Ssam inp->inp_faddr.s_addr = INADDR_ANY; 1936028Sroot inp->inp_fport = 0; 1947506Sroot if (inp->inp_socket->so_state & SS_NOFDREF) 1955161Swnj in_pcbdetach(inp); 1965161Swnj } 1975161Swnj 1985161Swnj in_pcbdetach(inp) 1995161Swnj struct inpcb *inp; 2005161Swnj { 2014905Swnj struct socket *so = inp->inp_socket; 2024905Swnj 2035009Swnj so->so_pcb = 0; 2045009Swnj sofree(so); 2056350Ssam if (inp->inp_route.ro_rt) 2066367Ssam rtfree(inp->inp_route.ro_rt); 2074983Swnj remque(inp); 2084907Swnj (void) m_free(dtom(inp)); 2094905Swnj } 2104905Swnj 2118270Sroot in_setsockaddr(inp, nam) 2126509Ssam register struct inpcb *inp; 2138270Sroot struct mbuf *nam; 2146509Ssam { 2158270Sroot register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); 2168270Sroot 2178270Sroot nam->m_len = sizeof (*sin); 2188270Sroot sin = mtod(nam, struct sockaddr_in *); 2196509Ssam bzero((caddr_t)sin, sizeof (*sin)); 2206509Ssam sin->sin_family = AF_INET; 2216509Ssam sin->sin_port = inp->inp_lport; 2226509Ssam sin->sin_addr = inp->inp_laddr; 2236509Ssam } 2246509Ssam 22514123Ssam in_setpeeraddr(inp, nam) 22614123Ssam register struct inpcb *inp; 22714123Ssam struct mbuf *nam; 22814123Ssam { 22914123Ssam register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); 23014123Ssam 23114123Ssam nam->m_len = sizeof (*sin); 23214123Ssam sin = mtod(nam, struct sockaddr_in *); 23314123Ssam bzero((caddr_t)sin, sizeof (*sin)); 23414123Ssam sin->sin_family = AF_INET; 23514123Ssam sin->sin_port = inp->inp_fport; 23614123Ssam sin->sin_addr = inp->inp_faddr; 23714123Ssam } 23814123Ssam 2395161Swnj /* 24017357Skarels * Pass some notification to all connections of a protocol 24117357Skarels * associated with address dst. Call the 24217357Skarels * protocol specific routine to handle each connection. 2436583Ssam */ 24417357Skarels in_pcbnotify(head, dst, errno, notify) 2456583Ssam struct inpcb *head; 2466583Ssam register struct in_addr *dst; 24717357Skarels int errno, (*notify)(); 2486583Ssam { 2496583Ssam register struct inpcb *inp, *oinp; 2506583Ssam int s = splimp(); 2516583Ssam 2526583Ssam for (inp = head->inp_next; inp != head;) { 2536583Ssam if (inp->inp_faddr.s_addr != dst->s_addr) { 2546583Ssam next: 2556583Ssam inp = inp->inp_next; 2566583Ssam continue; 2576583Ssam } 2586583Ssam if (inp->inp_socket == 0) 2596583Ssam goto next; 26017357Skarels if (errno) 26117357Skarels inp->inp_socket->so_error = errno; 2626583Ssam oinp = inp; 2636583Ssam inp = inp->inp_next; 26417357Skarels (*notify)(oinp); 2656583Ssam } 2666583Ssam splx(s); 2676583Ssam } 2686583Ssam 26917357Skarels /* 27017357Skarels * After a routing change, flush old routing 27117357Skarels * and allocate a (hopefully) better one. 27217357Skarels */ 27317357Skarels in_rtchange(inp) 27417357Skarels struct inpcb *inp; 27517357Skarels { 27617357Skarels if (inp->inp_route.ro_rt) { 27717357Skarels rtfree(inp->inp_route.ro_rt); 27817357Skarels inp->inp_route.ro_rt = 0; 27917357Skarels /* 28017357Skarels * A new route can be allocated the next time 28117357Skarels * output is attempted. 28217357Skarels */ 28317357Skarels } 28417357Skarels /* SHOULD NOTIFY HIGHER-LEVEL PROTOCOLS */ 28517357Skarels } 28617357Skarels 2874907Swnj struct inpcb * 2886028Sroot in_pcblookup(head, faddr, fport, laddr, lport, flags) 2894905Swnj struct inpcb *head; 2904951Swnj struct in_addr faddr, laddr; 2914905Swnj u_short fport, lport; 2926028Sroot int flags; 2934905Swnj { 2945994Swnj register struct inpcb *inp, *match = 0; 2955994Swnj int matchwild = 3, wildcard; 2964905Swnj 2975161Swnj for (inp = head->inp_next; inp != head; inp = inp->inp_next) { 2985994Swnj if (inp->inp_lport != lport) 2995161Swnj continue; 3005994Swnj wildcard = 0; 30110141Ssam if (inp->inp_laddr.s_addr != INADDR_ANY) { 30210141Ssam if (laddr.s_addr == INADDR_ANY) 3036116Swnj wildcard++; 3046116Swnj else if (inp->inp_laddr.s_addr != laddr.s_addr) 3055994Swnj continue; 3065994Swnj } else { 30710141Ssam if (laddr.s_addr != INADDR_ANY) 3085994Swnj wildcard++; 3095994Swnj } 31010141Ssam if (inp->inp_faddr.s_addr != INADDR_ANY) { 31110141Ssam if (faddr.s_addr == INADDR_ANY) 3126116Swnj wildcard++; 3136116Swnj else if (inp->inp_faddr.s_addr != faddr.s_addr || 3146028Sroot inp->inp_fport != fport) 3155994Swnj continue; 3165994Swnj } else { 31710141Ssam if (faddr.s_addr != INADDR_ANY) 3185994Swnj wildcard++; 3195994Swnj } 3206028Sroot if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0) 3215994Swnj continue; 3225994Swnj if (wildcard < matchwild) { 3235161Swnj match = inp; 3245994Swnj matchwild = wildcard; 3255994Swnj if (matchwild == 0) 3265994Swnj break; 3275161Swnj } 3285161Swnj } 3295161Swnj return (match); 3304905Swnj } 331