123177Smckusick /* 2*48464Skarels * Copyright (c) 1982, 1986, 1991 Regents of the University of California. 332787Sbostic * All rights reserved. 423177Smckusick * 544475Sbostic * %sccs.include.redist.c% 632787Sbostic * 7*48464Skarels * @(#)in_pcb.c 7.14 (Berkeley) 04/20/91 823177Smckusick */ 94905Swnj 1017058Sbloom #include "param.h" 1117058Sbloom #include "systm.h" 1235794Skarels #include "malloc.h" 1317058Sbloom #include "mbuf.h" 14*48464Skarels #include "protosw.h" 1517058Sbloom #include "socket.h" 1617058Sbloom #include "socketvar.h" 1725508Skarels #include "ioctl.h" 18*48464Skarels 1940692Skarels #include "../net/if.h" 2040692Skarels #include "../net/route.h" 21*48464Skarels 2217058Sbloom #include "in.h" 2317058Sbloom #include "in_systm.h" 2440692Skarels #include "ip.h" 2517058Sbloom #include "in_pcb.h" 2618374Skarels #include "in_var.h" 274905Swnj 285240Sroot struct in_addr zeroin_addr; 295161Swnj 307506Sroot in_pcballoc(so, head) 317506Sroot struct socket *so; 327506Sroot struct inpcb *head; 337506Sroot { 347506Sroot struct mbuf *m; 357506Sroot register struct inpcb *inp; 367506Sroot 379639Ssam m = m_getclr(M_DONTWAIT, MT_PCB); 3810141Ssam if (m == NULL) 397506Sroot return (ENOBUFS); 407506Sroot inp = mtod(m, struct inpcb *); 417506Sroot inp->inp_head = head; 427506Sroot inp->inp_socket = so; 437506Sroot insque(inp, head); 447506Sroot so->so_pcb = (caddr_t)inp; 457506Sroot return (0); 467506Sroot } 477506Sroot 488270Sroot in_pcbbind(inp, nam) 497506Sroot register struct inpcb *inp; 508270Sroot struct mbuf *nam; 517506Sroot { 527506Sroot register struct socket *so = inp->inp_socket; 537506Sroot register struct inpcb *head = inp->inp_head; 548270Sroot register struct sockaddr_in *sin; 557506Sroot u_short lport = 0; 567506Sroot 5718374Skarels if (in_ifaddr == 0) 587506Sroot return (EADDRNOTAVAIL); 5910141Ssam if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY) 608270Sroot return (EINVAL); 618270Sroot if (nam == 0) 628270Sroot goto noname; 638270Sroot sin = mtod(nam, struct sockaddr_in *); 648270Sroot if (nam->m_len != sizeof (*sin)) 658270Sroot return (EINVAL); 6610141Ssam if (sin->sin_addr.s_addr != INADDR_ANY) { 678270Sroot int tport = sin->sin_port; 687506Sroot 698270Sroot sin->sin_port = 0; /* yech... */ 7018374Skarels if (ifa_ifwithaddr((struct sockaddr *)sin) == 0) 718270Sroot return (EADDRNOTAVAIL); 728270Sroot sin->sin_port = tport; 737506Sroot } 748270Sroot lport = sin->sin_port; 758270Sroot if (lport) { 7617429Skarels u_short aport = ntohs(lport); 778270Sroot int wild = 0; 787506Sroot 798270Sroot /* GROSS */ 80*48464Skarels if (aport < IPPORT_RESERVED && (so->so_state & SS_PRIV) == 0) 818270Sroot return (EACCES); 8210598Ssam /* even GROSSER, but this is the Internet */ 8310598Ssam if ((so->so_options & SO_REUSEADDR) == 0 && 8410598Ssam ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 || 8510598Ssam (so->so_options & SO_ACCEPTCONN) == 0)) 868270Sroot wild = INPLOOKUP_WILDCARD; 878270Sroot if (in_pcblookup(head, 888270Sroot zeroin_addr, 0, sin->sin_addr, lport, wild)) 898270Sroot return (EADDRINUSE); 904951Swnj } 918270Sroot inp->inp_laddr = sin->sin_addr; 928270Sroot noname: 935172Swnj if (lport == 0) 945172Swnj do { 9526025Skarels if (head->inp_lport++ < IPPORT_RESERVED || 9626025Skarels head->inp_lport > IPPORT_USERRESERVED) 975994Swnj head->inp_lport = IPPORT_RESERVED; 985172Swnj lport = htons(head->inp_lport); 995994Swnj } while (in_pcblookup(head, 1005994Swnj zeroin_addr, 0, inp->inp_laddr, lport, 0)); 1015172Swnj inp->inp_lport = lport; 1024951Swnj return (0); 1034905Swnj } 1044905Swnj 1056116Swnj /* 1066116Swnj * Connect from a socket to a specified address. 1076116Swnj * Both address and port must be specified in argument sin. 1086116Swnj * If don't have a local address for this socket yet, 1096116Swnj * then pick one. 1106116Swnj */ 1118270Sroot in_pcbconnect(inp, nam) 11231976Skarels register struct inpcb *inp; 1138270Sroot struct mbuf *nam; 1144923Swnj { 11518374Skarels struct in_ifaddr *ia; 1166338Ssam struct sockaddr_in *ifaddr; 1178270Sroot register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); 1184923Swnj 1198270Sroot if (nam->m_len != sizeof (*sin)) 1208270Sroot return (EINVAL); 1214951Swnj if (sin->sin_family != AF_INET) 1224951Swnj return (EAFNOSUPPORT); 12318374Skarels if (sin->sin_port == 0) 1244951Swnj return (EADDRNOTAVAIL); 12518374Skarels if (in_ifaddr) { 12618655Skarels /* 12718655Skarels * If the destination address is INADDR_ANY, 12818655Skarels * use the primary local address. 12918655Skarels * If the supplied address is INADDR_BROADCAST, 13018655Skarels * and the primary interface supports broadcast, 13118655Skarels * choose the broadcast address for that interface. 13218655Skarels */ 13318374Skarels #define satosin(sa) ((struct sockaddr_in *)(sa)) 13418374Skarels if (sin->sin_addr.s_addr == INADDR_ANY) 13518655Skarels sin->sin_addr = IA_SIN(in_ifaddr)->sin_addr; 13624807Skarels else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST && 13718655Skarels (in_ifaddr->ia_ifp->if_flags & IFF_BROADCAST)) 13818655Skarels sin->sin_addr = satosin(&in_ifaddr->ia_broadaddr)->sin_addr; 13918374Skarels } 14010141Ssam if (inp->inp_laddr.s_addr == INADDR_ANY) { 14127262Skarels register struct route *ro; 14227262Skarels struct ifnet *ifp; 14317271Skarels 14427262Skarels ia = (struct in_ifaddr *)0; 14527262Skarels /* 14627262Skarels * If route is known or can be allocated now, 14727262Skarels * our src addr is taken from the i/f, else punt. 14827262Skarels */ 14927262Skarels ro = &inp->inp_route; 15027262Skarels if (ro->ro_rt && 15130336Skarels (satosin(&ro->ro_dst)->sin_addr.s_addr != 15230336Skarels sin->sin_addr.s_addr || 15330336Skarels inp->inp_socket->so_options & SO_DONTROUTE)) { 15427262Skarels RTFREE(ro->ro_rt); 15527262Skarels ro->ro_rt = (struct rtentry *)0; 1566338Ssam } 15728847Skarels if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/ 15828847Skarels (ro->ro_rt == (struct rtentry *)0 || 15929826Skarels ro->ro_rt->rt_ifp == (struct ifnet *)0)) { 16027262Skarels /* No route yet, so try to acquire one */ 16127262Skarels ro->ro_dst.sa_family = AF_INET; 16237471Ssklower ro->ro_dst.sa_len = sizeof(struct sockaddr_in); 16327262Skarels ((struct sockaddr_in *) &ro->ro_dst)->sin_addr = 16427262Skarels sin->sin_addr; 16527262Skarels rtalloc(ro); 16627262Skarels } 16729826Skarels /* 16829826Skarels * If we found a route, use the address 16929826Skarels * corresponding to the outgoing interface 17029826Skarels * unless it is the loopback (in case a route 17129826Skarels * to our address on another net goes to loopback). 17229826Skarels */ 17329826Skarels if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp) && 17429826Skarels (ifp->if_flags & IFF_LOOPBACK) == 0) 17529826Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 17629826Skarels if (ia->ia_ifp == ifp) 17729826Skarels break; 17828847Skarels if (ia == 0) { 17930336Skarels int fport = sin->sin_port; 18030336Skarels 18130336Skarels sin->sin_port = 0; 18228847Skarels ia = (struct in_ifaddr *) 18328847Skarels ifa_ifwithdstaddr((struct sockaddr *)sin); 18430336Skarels sin->sin_port = fport; 18528847Skarels if (ia == 0) 18628847Skarels ia = in_iaonnetof(in_netof(sin->sin_addr)); 18728847Skarels if (ia == 0) 18828847Skarels ia = in_ifaddr; 18928847Skarels if (ia == 0) 19028847Skarels return (EADDRNOTAVAIL); 19127262Skarels } 19218374Skarels ifaddr = (struct sockaddr_in *)&ia->ia_addr; 1935994Swnj } 1945994Swnj if (in_pcblookup(inp->inp_head, 1956116Swnj sin->sin_addr, 1966116Swnj sin->sin_port, 1976338Ssam inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr, 1986116Swnj inp->inp_lport, 1996116Swnj 0)) 2005172Swnj return (EADDRINUSE); 20114146Ssam if (inp->inp_laddr.s_addr == INADDR_ANY) { 20214146Ssam if (inp->inp_lport == 0) 20326382Skarels (void)in_pcbbind(inp, (struct mbuf *)0); 2046338Ssam inp->inp_laddr = ifaddr->sin_addr; 20514146Ssam } 2064951Swnj inp->inp_faddr = sin->sin_addr; 2074951Swnj inp->inp_fport = sin->sin_port; 2084923Swnj return (0); 2094923Swnj } 2104923Swnj 2115161Swnj in_pcbdisconnect(inp) 2124905Swnj struct inpcb *inp; 2134905Swnj { 2145161Swnj 21510141Ssam inp->inp_faddr.s_addr = INADDR_ANY; 2166028Sroot inp->inp_fport = 0; 2177506Sroot if (inp->inp_socket->so_state & SS_NOFDREF) 2185161Swnj in_pcbdetach(inp); 2195161Swnj } 2205161Swnj 2215161Swnj in_pcbdetach(inp) 2225161Swnj struct inpcb *inp; 2235161Swnj { 2244905Swnj struct socket *so = inp->inp_socket; 2254905Swnj 2265009Swnj so->so_pcb = 0; 2275009Swnj sofree(so); 22824807Skarels if (inp->inp_options) 22926382Skarels (void)m_free(inp->inp_options); 2306350Ssam if (inp->inp_route.ro_rt) 2316367Ssam rtfree(inp->inp_route.ro_rt); 2324983Swnj remque(inp); 2334907Swnj (void) m_free(dtom(inp)); 2344905Swnj } 2354905Swnj 2368270Sroot in_setsockaddr(inp, nam) 2376509Ssam register struct inpcb *inp; 2388270Sroot struct mbuf *nam; 2396509Ssam { 24032071Skarels register struct sockaddr_in *sin; 2418270Sroot 2428270Sroot nam->m_len = sizeof (*sin); 2438270Sroot sin = mtod(nam, struct sockaddr_in *); 2446509Ssam bzero((caddr_t)sin, sizeof (*sin)); 2456509Ssam sin->sin_family = AF_INET; 24637471Ssklower sin->sin_len = sizeof(*sin); 2476509Ssam sin->sin_port = inp->inp_lport; 2486509Ssam sin->sin_addr = inp->inp_laddr; 2496509Ssam } 2506509Ssam 25114123Ssam in_setpeeraddr(inp, nam) 25231976Skarels struct inpcb *inp; 25314123Ssam struct mbuf *nam; 25414123Ssam { 25532071Skarels register struct sockaddr_in *sin; 25614123Ssam 25714123Ssam nam->m_len = sizeof (*sin); 25814123Ssam sin = mtod(nam, struct sockaddr_in *); 25914123Ssam bzero((caddr_t)sin, sizeof (*sin)); 26014123Ssam sin->sin_family = AF_INET; 26137471Ssklower sin->sin_len = sizeof(*sin); 26214123Ssam sin->sin_port = inp->inp_fport; 26314123Ssam sin->sin_addr = inp->inp_faddr; 26414123Ssam } 26514123Ssam 2665161Swnj /* 26717357Skarels * Pass some notification to all connections of a protocol 26840692Skarels * associated with address dst. The local address and/or port numbers 26940692Skarels * may be specified to limit the search. The "usual action" will be 27040692Skarels * taken, depending on the ctlinput cmd. The caller must filter any 27140692Skarels * cmds that are uninteresting (e.g., no error in the map). 27240692Skarels * Call the protocol specific routine (if any) to report 27340692Skarels * any errors for each matching socket. 27440692Skarels * 27540692Skarels * Must be called at splnet. 2766583Ssam */ 27740692Skarels in_pcbnotify(head, dst, fport, laddr, lport, cmd, notify) 2786583Ssam struct inpcb *head; 27940692Skarels struct sockaddr *dst; 28040692Skarels u_short fport, lport; 28140692Skarels struct in_addr laddr; 28240692Skarels int cmd, (*notify)(); 2836583Ssam { 2846583Ssam register struct inpcb *inp, *oinp; 28540692Skarels struct in_addr faddr; 28640692Skarels int errno; 28740692Skarels int in_rtchange(); 28840692Skarels extern u_char inetctlerrmap[]; 2896583Ssam 29040692Skarels if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET) 29140692Skarels return; 29240692Skarels faddr = ((struct sockaddr_in *)dst)->sin_addr; 29340692Skarels if (faddr.s_addr == INADDR_ANY) 29440692Skarels return; 29540692Skarels 29640692Skarels /* 29740692Skarels * Redirects go to all references to the destination, 29840692Skarels * and use in_rtchange to invalidate the route cache. 29940692Skarels * Dead host indications: notify all references to the destination. 30040692Skarels * Otherwise, if we have knowledge of the local port and address, 30140692Skarels * deliver only to that socket. 30240692Skarels */ 30340692Skarels if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) { 30440692Skarels fport = 0; 30540692Skarels lport = 0; 30640692Skarels laddr.s_addr = 0; 30740692Skarels if (cmd != PRC_HOSTDEAD) 30840692Skarels notify = in_rtchange; 30940692Skarels } 31040692Skarels errno = inetctlerrmap[cmd]; 3116583Ssam for (inp = head->inp_next; inp != head;) { 31240692Skarels if (inp->inp_faddr.s_addr != faddr.s_addr || 31340692Skarels inp->inp_socket == 0 || 31440692Skarels (lport && inp->inp_lport != lport) || 31540692Skarels (laddr.s_addr && inp->inp_laddr.s_addr != laddr.s_addr) || 31640692Skarels (fport && inp->inp_fport != fport)) { 3176583Ssam inp = inp->inp_next; 3186583Ssam continue; 3196583Ssam } 3206583Ssam oinp = inp; 3216583Ssam inp = inp->inp_next; 32224807Skarels if (notify) 32344381Skarels (*notify)(oinp, errno); 3246583Ssam } 3256583Ssam } 3266583Ssam 32717357Skarels /* 32825508Skarels * Check for alternatives when higher level complains 32925508Skarels * about service problems. For now, invalidate cached 33025508Skarels * routing information. If the route was created dynamically 33125508Skarels * (by a redirect), time to try a default gateway again. 33225508Skarels */ 33325508Skarels in_losing(inp) 33425508Skarels struct inpcb *inp; 33525508Skarels { 33625508Skarels register struct rtentry *rt; 33725508Skarels 33825508Skarels if ((rt = inp->inp_route.ro_rt)) { 33937471Ssklower rt_missmsg(RTM_LOSING, &inp->inp_route.ro_dst, 34037471Ssklower rt->rt_gateway, (struct sockaddr *)rt_mask(rt), 34137471Ssklower (struct sockaddr *)0, rt->rt_flags, 0); 34225508Skarels if (rt->rt_flags & RTF_DYNAMIC) 34337471Ssklower (void) rtrequest(RTM_DELETE, rt_key(rt), 34437471Ssklower rt->rt_gateway, rt_mask(rt), rt->rt_flags, 34537471Ssklower (struct rtentry **)0); 34637471Ssklower inp->inp_route.ro_rt = 0; 34725508Skarels rtfree(rt); 34825508Skarels /* 34925508Skarels * A new route can be allocated 35025508Skarels * the next time output is attempted. 35125508Skarels */ 35225508Skarels } 35325508Skarels } 35425508Skarels 35525508Skarels /* 35617357Skarels * After a routing change, flush old routing 35717357Skarels * and allocate a (hopefully) better one. 35817357Skarels */ 35917357Skarels in_rtchange(inp) 36025508Skarels register struct inpcb *inp; 36117357Skarels { 36217357Skarels if (inp->inp_route.ro_rt) { 36317357Skarels rtfree(inp->inp_route.ro_rt); 36417357Skarels inp->inp_route.ro_rt = 0; 36517357Skarels /* 36617357Skarels * A new route can be allocated the next time 36717357Skarels * output is attempted. 36817357Skarels */ 36917357Skarels } 37017357Skarels } 37117357Skarels 3724907Swnj struct inpcb * 3736028Sroot in_pcblookup(head, faddr, fport, laddr, lport, flags) 3744905Swnj struct inpcb *head; 3754951Swnj struct in_addr faddr, laddr; 3764905Swnj u_short fport, lport; 3776028Sroot int flags; 3784905Swnj { 3795994Swnj register struct inpcb *inp, *match = 0; 3805994Swnj int matchwild = 3, wildcard; 3814905Swnj 3825161Swnj for (inp = head->inp_next; inp != head; inp = inp->inp_next) { 3835994Swnj if (inp->inp_lport != lport) 3845161Swnj continue; 3855994Swnj wildcard = 0; 38610141Ssam if (inp->inp_laddr.s_addr != INADDR_ANY) { 38710141Ssam if (laddr.s_addr == INADDR_ANY) 3886116Swnj wildcard++; 3896116Swnj else if (inp->inp_laddr.s_addr != laddr.s_addr) 3905994Swnj continue; 3915994Swnj } else { 39210141Ssam if (laddr.s_addr != INADDR_ANY) 3935994Swnj wildcard++; 3945994Swnj } 39510141Ssam if (inp->inp_faddr.s_addr != INADDR_ANY) { 39610141Ssam if (faddr.s_addr == INADDR_ANY) 3976116Swnj wildcard++; 3986116Swnj else if (inp->inp_faddr.s_addr != faddr.s_addr || 3996028Sroot inp->inp_fport != fport) 4005994Swnj continue; 4015994Swnj } else { 40210141Ssam if (faddr.s_addr != INADDR_ANY) 4035994Swnj wildcard++; 4045994Swnj } 4056028Sroot if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0) 4065994Swnj continue; 4075994Swnj if (wildcard < matchwild) { 4085161Swnj match = inp; 4095994Swnj matchwild = wildcard; 4105994Swnj if (matchwild == 0) 4115994Swnj break; 4125161Swnj } 4135161Swnj } 4145161Swnj return (match); 4154905Swnj } 416