123177Smckusick /* 229138Smckusick * Copyright (c) 1982, 1986 Regents of the University of California. 332787Sbostic * All rights reserved. 423177Smckusick * 5*44475Sbostic * %sccs.include.redist.c% 632787Sbostic * 7*44475Sbostic * @(#)in_pcb.c 7.13 (Berkeley) 06/28/90 823177Smckusick */ 94905Swnj 1017058Sbloom #include "param.h" 1117058Sbloom #include "systm.h" 1217058Sbloom #include "user.h" 1335794Skarels #include "malloc.h" 1417058Sbloom #include "mbuf.h" 1517058Sbloom #include "socket.h" 1617058Sbloom #include "socketvar.h" 1725508Skarels #include "ioctl.h" 1840692Skarels #include "../net/if.h" 1940692Skarels #include "../net/route.h" 2017058Sbloom #include "in.h" 2117058Sbloom #include "in_systm.h" 2240692Skarels #include "ip.h" 2317058Sbloom #include "in_pcb.h" 2418374Skarels #include "in_var.h" 2517058Sbloom #include "protosw.h" 264905Swnj 275240Sroot struct in_addr zeroin_addr; 285161Swnj 297506Sroot in_pcballoc(so, head) 307506Sroot struct socket *so; 317506Sroot struct inpcb *head; 327506Sroot { 337506Sroot struct mbuf *m; 347506Sroot register struct inpcb *inp; 357506Sroot 369639Ssam m = m_getclr(M_DONTWAIT, MT_PCB); 3710141Ssam if (m == NULL) 387506Sroot return (ENOBUFS); 397506Sroot inp = mtod(m, struct inpcb *); 407506Sroot inp->inp_head = head; 417506Sroot inp->inp_socket = so; 427506Sroot insque(inp, head); 437506Sroot so->so_pcb = (caddr_t)inp; 447506Sroot return (0); 457506Sroot } 467506Sroot 478270Sroot in_pcbbind(inp, nam) 487506Sroot register struct inpcb *inp; 498270Sroot struct mbuf *nam; 507506Sroot { 517506Sroot register struct socket *so = inp->inp_socket; 527506Sroot register struct inpcb *head = inp->inp_head; 538270Sroot register struct sockaddr_in *sin; 547506Sroot u_short lport = 0; 557506Sroot 5618374Skarels if (in_ifaddr == 0) 577506Sroot return (EADDRNOTAVAIL); 5810141Ssam if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY) 598270Sroot return (EINVAL); 608270Sroot if (nam == 0) 618270Sroot goto noname; 628270Sroot sin = mtod(nam, struct sockaddr_in *); 638270Sroot if (nam->m_len != sizeof (*sin)) 648270Sroot return (EINVAL); 6510141Ssam if (sin->sin_addr.s_addr != INADDR_ANY) { 668270Sroot int tport = sin->sin_port; 677506Sroot 688270Sroot sin->sin_port = 0; /* yech... */ 6918374Skarels if (ifa_ifwithaddr((struct sockaddr *)sin) == 0) 708270Sroot return (EADDRNOTAVAIL); 718270Sroot sin->sin_port = tport; 727506Sroot } 738270Sroot lport = sin->sin_port; 748270Sroot if (lport) { 7517429Skarels u_short aport = ntohs(lport); 768270Sroot int wild = 0; 777506Sroot 788270Sroot /* GROSS */ 798270Sroot if (aport < IPPORT_RESERVED && u.u_uid != 0) 808270Sroot return (EACCES); 8110598Ssam /* even GROSSER, but this is the Internet */ 8210598Ssam if ((so->so_options & SO_REUSEADDR) == 0 && 8310598Ssam ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 || 8410598Ssam (so->so_options & SO_ACCEPTCONN) == 0)) 858270Sroot wild = INPLOOKUP_WILDCARD; 868270Sroot if (in_pcblookup(head, 878270Sroot zeroin_addr, 0, sin->sin_addr, lport, wild)) 888270Sroot return (EADDRINUSE); 894951Swnj } 908270Sroot inp->inp_laddr = sin->sin_addr; 918270Sroot noname: 925172Swnj if (lport == 0) 935172Swnj do { 9426025Skarels if (head->inp_lport++ < IPPORT_RESERVED || 9526025Skarels head->inp_lport > IPPORT_USERRESERVED) 965994Swnj head->inp_lport = IPPORT_RESERVED; 975172Swnj lport = htons(head->inp_lport); 985994Swnj } while (in_pcblookup(head, 995994Swnj zeroin_addr, 0, inp->inp_laddr, lport, 0)); 1005172Swnj inp->inp_lport = lport; 1014951Swnj return (0); 1024905Swnj } 1034905Swnj 1046116Swnj /* 1056116Swnj * Connect from a socket to a specified address. 1066116Swnj * Both address and port must be specified in argument sin. 1076116Swnj * If don't have a local address for this socket yet, 1086116Swnj * then pick one. 1096116Swnj */ 1108270Sroot in_pcbconnect(inp, nam) 11131976Skarels register struct inpcb *inp; 1128270Sroot struct mbuf *nam; 1134923Swnj { 11418374Skarels struct in_ifaddr *ia; 1156338Ssam struct sockaddr_in *ifaddr; 1168270Sroot register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); 1174923Swnj 1188270Sroot if (nam->m_len != sizeof (*sin)) 1198270Sroot return (EINVAL); 1204951Swnj if (sin->sin_family != AF_INET) 1214951Swnj return (EAFNOSUPPORT); 12218374Skarels if (sin->sin_port == 0) 1234951Swnj return (EADDRNOTAVAIL); 12418374Skarels if (in_ifaddr) { 12518655Skarels /* 12618655Skarels * If the destination address is INADDR_ANY, 12718655Skarels * use the primary local address. 12818655Skarels * If the supplied address is INADDR_BROADCAST, 12918655Skarels * and the primary interface supports broadcast, 13018655Skarels * choose the broadcast address for that interface. 13118655Skarels */ 13218374Skarels #define satosin(sa) ((struct sockaddr_in *)(sa)) 13318374Skarels if (sin->sin_addr.s_addr == INADDR_ANY) 13418655Skarels sin->sin_addr = IA_SIN(in_ifaddr)->sin_addr; 13524807Skarels else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST && 13618655Skarels (in_ifaddr->ia_ifp->if_flags & IFF_BROADCAST)) 13718655Skarels sin->sin_addr = satosin(&in_ifaddr->ia_broadaddr)->sin_addr; 13818374Skarels } 13910141Ssam if (inp->inp_laddr.s_addr == INADDR_ANY) { 14027262Skarels register struct route *ro; 14127262Skarels struct ifnet *ifp; 14217271Skarels 14327262Skarels ia = (struct in_ifaddr *)0; 14427262Skarels /* 14527262Skarels * If route is known or can be allocated now, 14627262Skarels * our src addr is taken from the i/f, else punt. 14727262Skarels */ 14827262Skarels ro = &inp->inp_route; 14927262Skarels if (ro->ro_rt && 15030336Skarels (satosin(&ro->ro_dst)->sin_addr.s_addr != 15130336Skarels sin->sin_addr.s_addr || 15230336Skarels inp->inp_socket->so_options & SO_DONTROUTE)) { 15327262Skarels RTFREE(ro->ro_rt); 15427262Skarels ro->ro_rt = (struct rtentry *)0; 1556338Ssam } 15628847Skarels if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/ 15728847Skarels (ro->ro_rt == (struct rtentry *)0 || 15829826Skarels ro->ro_rt->rt_ifp == (struct ifnet *)0)) { 15927262Skarels /* No route yet, so try to acquire one */ 16027262Skarels ro->ro_dst.sa_family = AF_INET; 16137471Ssklower ro->ro_dst.sa_len = sizeof(struct sockaddr_in); 16227262Skarels ((struct sockaddr_in *) &ro->ro_dst)->sin_addr = 16327262Skarels sin->sin_addr; 16427262Skarels rtalloc(ro); 16527262Skarels } 16629826Skarels /* 16729826Skarels * If we found a route, use the address 16829826Skarels * corresponding to the outgoing interface 16929826Skarels * unless it is the loopback (in case a route 17029826Skarels * to our address on another net goes to loopback). 17129826Skarels */ 17229826Skarels if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp) && 17329826Skarels (ifp->if_flags & IFF_LOOPBACK) == 0) 17429826Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 17529826Skarels if (ia->ia_ifp == ifp) 17629826Skarels break; 17728847Skarels if (ia == 0) { 17830336Skarels int fport = sin->sin_port; 17930336Skarels 18030336Skarels sin->sin_port = 0; 18128847Skarels ia = (struct in_ifaddr *) 18228847Skarels ifa_ifwithdstaddr((struct sockaddr *)sin); 18330336Skarels sin->sin_port = fport; 18428847Skarels if (ia == 0) 18528847Skarels ia = in_iaonnetof(in_netof(sin->sin_addr)); 18628847Skarels if (ia == 0) 18728847Skarels ia = in_ifaddr; 18828847Skarels if (ia == 0) 18928847Skarels return (EADDRNOTAVAIL); 19027262Skarels } 19118374Skarels ifaddr = (struct sockaddr_in *)&ia->ia_addr; 1925994Swnj } 1935994Swnj if (in_pcblookup(inp->inp_head, 1946116Swnj sin->sin_addr, 1956116Swnj sin->sin_port, 1966338Ssam inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr, 1976116Swnj inp->inp_lport, 1986116Swnj 0)) 1995172Swnj return (EADDRINUSE); 20014146Ssam if (inp->inp_laddr.s_addr == INADDR_ANY) { 20114146Ssam if (inp->inp_lport == 0) 20226382Skarels (void)in_pcbbind(inp, (struct mbuf *)0); 2036338Ssam inp->inp_laddr = ifaddr->sin_addr; 20414146Ssam } 2054951Swnj inp->inp_faddr = sin->sin_addr; 2064951Swnj inp->inp_fport = sin->sin_port; 2074923Swnj return (0); 2084923Swnj } 2094923Swnj 2105161Swnj in_pcbdisconnect(inp) 2114905Swnj struct inpcb *inp; 2124905Swnj { 2135161Swnj 21410141Ssam inp->inp_faddr.s_addr = INADDR_ANY; 2156028Sroot inp->inp_fport = 0; 2167506Sroot if (inp->inp_socket->so_state & SS_NOFDREF) 2175161Swnj in_pcbdetach(inp); 2185161Swnj } 2195161Swnj 2205161Swnj in_pcbdetach(inp) 2215161Swnj struct inpcb *inp; 2225161Swnj { 2234905Swnj struct socket *so = inp->inp_socket; 2244905Swnj 2255009Swnj so->so_pcb = 0; 2265009Swnj sofree(so); 22724807Skarels if (inp->inp_options) 22826382Skarels (void)m_free(inp->inp_options); 2296350Ssam if (inp->inp_route.ro_rt) 2306367Ssam rtfree(inp->inp_route.ro_rt); 2314983Swnj remque(inp); 2324907Swnj (void) m_free(dtom(inp)); 2334905Swnj } 2344905Swnj 2358270Sroot in_setsockaddr(inp, nam) 2366509Ssam register struct inpcb *inp; 2378270Sroot struct mbuf *nam; 2386509Ssam { 23932071Skarels register struct sockaddr_in *sin; 2408270Sroot 2418270Sroot nam->m_len = sizeof (*sin); 2428270Sroot sin = mtod(nam, struct sockaddr_in *); 2436509Ssam bzero((caddr_t)sin, sizeof (*sin)); 2446509Ssam sin->sin_family = AF_INET; 24537471Ssklower sin->sin_len = sizeof(*sin); 2466509Ssam sin->sin_port = inp->inp_lport; 2476509Ssam sin->sin_addr = inp->inp_laddr; 2486509Ssam } 2496509Ssam 25014123Ssam in_setpeeraddr(inp, nam) 25131976Skarels struct inpcb *inp; 25214123Ssam struct mbuf *nam; 25314123Ssam { 25432071Skarels register struct sockaddr_in *sin; 25514123Ssam 25614123Ssam nam->m_len = sizeof (*sin); 25714123Ssam sin = mtod(nam, struct sockaddr_in *); 25814123Ssam bzero((caddr_t)sin, sizeof (*sin)); 25914123Ssam sin->sin_family = AF_INET; 26037471Ssklower sin->sin_len = sizeof(*sin); 26114123Ssam sin->sin_port = inp->inp_fport; 26214123Ssam sin->sin_addr = inp->inp_faddr; 26314123Ssam } 26414123Ssam 2655161Swnj /* 26617357Skarels * Pass some notification to all connections of a protocol 26740692Skarels * associated with address dst. The local address and/or port numbers 26840692Skarels * may be specified to limit the search. The "usual action" will be 26940692Skarels * taken, depending on the ctlinput cmd. The caller must filter any 27040692Skarels * cmds that are uninteresting (e.g., no error in the map). 27140692Skarels * Call the protocol specific routine (if any) to report 27240692Skarels * any errors for each matching socket. 27340692Skarels * 27440692Skarels * Must be called at splnet. 2756583Ssam */ 27640692Skarels in_pcbnotify(head, dst, fport, laddr, lport, cmd, notify) 2776583Ssam struct inpcb *head; 27840692Skarels struct sockaddr *dst; 27940692Skarels u_short fport, lport; 28040692Skarels struct in_addr laddr; 28140692Skarels int cmd, (*notify)(); 2826583Ssam { 2836583Ssam register struct inpcb *inp, *oinp; 28440692Skarels struct in_addr faddr; 28540692Skarels int errno; 28640692Skarels int in_rtchange(); 28740692Skarels extern u_char inetctlerrmap[]; 2886583Ssam 28940692Skarels if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET) 29040692Skarels return; 29140692Skarels faddr = ((struct sockaddr_in *)dst)->sin_addr; 29240692Skarels if (faddr.s_addr == INADDR_ANY) 29340692Skarels return; 29440692Skarels 29540692Skarels /* 29640692Skarels * Redirects go to all references to the destination, 29740692Skarels * and use in_rtchange to invalidate the route cache. 29840692Skarels * Dead host indications: notify all references to the destination. 29940692Skarels * Otherwise, if we have knowledge of the local port and address, 30040692Skarels * deliver only to that socket. 30140692Skarels */ 30240692Skarels if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) { 30340692Skarels fport = 0; 30440692Skarels lport = 0; 30540692Skarels laddr.s_addr = 0; 30640692Skarels if (cmd != PRC_HOSTDEAD) 30740692Skarels notify = in_rtchange; 30840692Skarels } 30940692Skarels errno = inetctlerrmap[cmd]; 3106583Ssam for (inp = head->inp_next; inp != head;) { 31140692Skarels if (inp->inp_faddr.s_addr != faddr.s_addr || 31240692Skarels inp->inp_socket == 0 || 31340692Skarels (lport && inp->inp_lport != lport) || 31440692Skarels (laddr.s_addr && inp->inp_laddr.s_addr != laddr.s_addr) || 31540692Skarels (fport && inp->inp_fport != fport)) { 3166583Ssam inp = inp->inp_next; 3176583Ssam continue; 3186583Ssam } 3196583Ssam oinp = inp; 3206583Ssam inp = inp->inp_next; 32124807Skarels if (notify) 32244381Skarels (*notify)(oinp, errno); 3236583Ssam } 3246583Ssam } 3256583Ssam 32617357Skarels /* 32725508Skarels * Check for alternatives when higher level complains 32825508Skarels * about service problems. For now, invalidate cached 32925508Skarels * routing information. If the route was created dynamically 33025508Skarels * (by a redirect), time to try a default gateway again. 33125508Skarels */ 33225508Skarels in_losing(inp) 33325508Skarels struct inpcb *inp; 33425508Skarels { 33525508Skarels register struct rtentry *rt; 33625508Skarels 33725508Skarels if ((rt = inp->inp_route.ro_rt)) { 33837471Ssklower rt_missmsg(RTM_LOSING, &inp->inp_route.ro_dst, 33937471Ssklower rt->rt_gateway, (struct sockaddr *)rt_mask(rt), 34037471Ssklower (struct sockaddr *)0, rt->rt_flags, 0); 34125508Skarels if (rt->rt_flags & RTF_DYNAMIC) 34237471Ssklower (void) rtrequest(RTM_DELETE, rt_key(rt), 34337471Ssklower rt->rt_gateway, rt_mask(rt), rt->rt_flags, 34437471Ssklower (struct rtentry **)0); 34537471Ssklower inp->inp_route.ro_rt = 0; 34625508Skarels rtfree(rt); 34725508Skarels /* 34825508Skarels * A new route can be allocated 34925508Skarels * the next time output is attempted. 35025508Skarels */ 35125508Skarels } 35225508Skarels } 35325508Skarels 35425508Skarels /* 35517357Skarels * After a routing change, flush old routing 35617357Skarels * and allocate a (hopefully) better one. 35717357Skarels */ 35817357Skarels in_rtchange(inp) 35925508Skarels register struct inpcb *inp; 36017357Skarels { 36117357Skarels if (inp->inp_route.ro_rt) { 36217357Skarels rtfree(inp->inp_route.ro_rt); 36317357Skarels inp->inp_route.ro_rt = 0; 36417357Skarels /* 36517357Skarels * A new route can be allocated the next time 36617357Skarels * output is attempted. 36717357Skarels */ 36817357Skarels } 36917357Skarels } 37017357Skarels 3714907Swnj struct inpcb * 3726028Sroot in_pcblookup(head, faddr, fport, laddr, lport, flags) 3734905Swnj struct inpcb *head; 3744951Swnj struct in_addr faddr, laddr; 3754905Swnj u_short fport, lport; 3766028Sroot int flags; 3774905Swnj { 3785994Swnj register struct inpcb *inp, *match = 0; 3795994Swnj int matchwild = 3, wildcard; 3804905Swnj 3815161Swnj for (inp = head->inp_next; inp != head; inp = inp->inp_next) { 3825994Swnj if (inp->inp_lport != lport) 3835161Swnj continue; 3845994Swnj wildcard = 0; 38510141Ssam if (inp->inp_laddr.s_addr != INADDR_ANY) { 38610141Ssam if (laddr.s_addr == INADDR_ANY) 3876116Swnj wildcard++; 3886116Swnj else if (inp->inp_laddr.s_addr != laddr.s_addr) 3895994Swnj continue; 3905994Swnj } else { 39110141Ssam if (laddr.s_addr != INADDR_ANY) 3925994Swnj wildcard++; 3935994Swnj } 39410141Ssam if (inp->inp_faddr.s_addr != INADDR_ANY) { 39510141Ssam if (faddr.s_addr == INADDR_ANY) 3966116Swnj wildcard++; 3976116Swnj else if (inp->inp_faddr.s_addr != faddr.s_addr || 3986028Sroot inp->inp_fport != fport) 3995994Swnj continue; 4005994Swnj } else { 40110141Ssam if (faddr.s_addr != INADDR_ANY) 4025994Swnj wildcard++; 4035994Swnj } 4046028Sroot if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0) 4055994Swnj continue; 4065994Swnj if (wildcard < matchwild) { 4075161Swnj match = inp; 4085994Swnj matchwild = wildcard; 4095994Swnj if (matchwild == 0) 4105994Swnj break; 4115161Swnj } 4125161Swnj } 4135161Swnj return (match); 4144905Swnj } 415