123177Smckusick /* 248464Skarels * Copyright (c) 1982, 1986, 1991 Regents of the University of California. 332787Sbostic * All rights reserved. 423177Smckusick * 544475Sbostic * %sccs.include.redist.c% 632787Sbostic * 7*51270Ssklower * @(#)in_pcb.c 7.15 (Berkeley) 10/02/91 823177Smckusick */ 94905Swnj 1017058Sbloom #include "param.h" 1117058Sbloom #include "systm.h" 1235794Skarels #include "malloc.h" 1317058Sbloom #include "mbuf.h" 1448464Skarels #include "protosw.h" 1517058Sbloom #include "socket.h" 1617058Sbloom #include "socketvar.h" 1725508Skarels #include "ioctl.h" 18*51270Ssklower #include "errno.h" 1948464Skarels 2040692Skarels #include "../net/if.h" 2140692Skarels #include "../net/route.h" 2248464Skarels 2317058Sbloom #include "in.h" 2417058Sbloom #include "in_systm.h" 2540692Skarels #include "ip.h" 2617058Sbloom #include "in_pcb.h" 2718374Skarels #include "in_var.h" 284905Swnj 295240Sroot struct in_addr zeroin_addr; 305161Swnj 317506Sroot in_pcballoc(so, head) 327506Sroot struct socket *so; 337506Sroot struct inpcb *head; 347506Sroot { 357506Sroot struct mbuf *m; 367506Sroot register struct inpcb *inp; 377506Sroot 389639Ssam m = m_getclr(M_DONTWAIT, MT_PCB); 3910141Ssam if (m == NULL) 407506Sroot return (ENOBUFS); 417506Sroot inp = mtod(m, struct inpcb *); 427506Sroot inp->inp_head = head; 437506Sroot inp->inp_socket = so; 447506Sroot insque(inp, head); 457506Sroot so->so_pcb = (caddr_t)inp; 467506Sroot return (0); 477506Sroot } 487506Sroot 498270Sroot in_pcbbind(inp, nam) 507506Sroot register struct inpcb *inp; 518270Sroot struct mbuf *nam; 527506Sroot { 537506Sroot register struct socket *so = inp->inp_socket; 547506Sroot register struct inpcb *head = inp->inp_head; 558270Sroot register struct sockaddr_in *sin; 567506Sroot u_short lport = 0; 577506Sroot 5818374Skarels if (in_ifaddr == 0) 597506Sroot return (EADDRNOTAVAIL); 6010141Ssam if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY) 618270Sroot return (EINVAL); 628270Sroot if (nam == 0) 638270Sroot goto noname; 648270Sroot sin = mtod(nam, struct sockaddr_in *); 658270Sroot if (nam->m_len != sizeof (*sin)) 668270Sroot return (EINVAL); 6710141Ssam if (sin->sin_addr.s_addr != INADDR_ANY) { 688270Sroot int tport = sin->sin_port; 697506Sroot 708270Sroot sin->sin_port = 0; /* yech... */ 7118374Skarels if (ifa_ifwithaddr((struct sockaddr *)sin) == 0) 728270Sroot return (EADDRNOTAVAIL); 738270Sroot sin->sin_port = tport; 747506Sroot } 758270Sroot lport = sin->sin_port; 768270Sroot if (lport) { 7717429Skarels u_short aport = ntohs(lport); 788270Sroot int wild = 0; 797506Sroot 808270Sroot /* GROSS */ 8148464Skarels if (aport < IPPORT_RESERVED && (so->so_state & SS_PRIV) == 0) 828270Sroot return (EACCES); 8310598Ssam /* even GROSSER, but this is the Internet */ 8410598Ssam if ((so->so_options & SO_REUSEADDR) == 0 && 8510598Ssam ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 || 8610598Ssam (so->so_options & SO_ACCEPTCONN) == 0)) 878270Sroot wild = INPLOOKUP_WILDCARD; 888270Sroot if (in_pcblookup(head, 898270Sroot zeroin_addr, 0, sin->sin_addr, lport, wild)) 908270Sroot return (EADDRINUSE); 914951Swnj } 928270Sroot inp->inp_laddr = sin->sin_addr; 938270Sroot noname: 945172Swnj if (lport == 0) 955172Swnj do { 9626025Skarels if (head->inp_lport++ < IPPORT_RESERVED || 9726025Skarels head->inp_lport > IPPORT_USERRESERVED) 985994Swnj head->inp_lport = IPPORT_RESERVED; 995172Swnj lport = htons(head->inp_lport); 1005994Swnj } while (in_pcblookup(head, 1015994Swnj zeroin_addr, 0, inp->inp_laddr, lport, 0)); 1025172Swnj inp->inp_lport = lport; 1034951Swnj return (0); 1044905Swnj } 1054905Swnj 1066116Swnj /* 1076116Swnj * Connect from a socket to a specified address. 1086116Swnj * Both address and port must be specified in argument sin. 1096116Swnj * If don't have a local address for this socket yet, 1106116Swnj * then pick one. 1116116Swnj */ 1128270Sroot in_pcbconnect(inp, nam) 11331976Skarels register struct inpcb *inp; 1148270Sroot struct mbuf *nam; 1154923Swnj { 11618374Skarels struct in_ifaddr *ia; 1176338Ssam struct sockaddr_in *ifaddr; 1188270Sroot register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); 1194923Swnj 1208270Sroot if (nam->m_len != sizeof (*sin)) 1218270Sroot return (EINVAL); 1224951Swnj if (sin->sin_family != AF_INET) 1234951Swnj return (EAFNOSUPPORT); 12418374Skarels if (sin->sin_port == 0) 1254951Swnj return (EADDRNOTAVAIL); 12618374Skarels if (in_ifaddr) { 12718655Skarels /* 12818655Skarels * If the destination address is INADDR_ANY, 12918655Skarels * use the primary local address. 13018655Skarels * If the supplied address is INADDR_BROADCAST, 13118655Skarels * and the primary interface supports broadcast, 13218655Skarels * choose the broadcast address for that interface. 13318655Skarels */ 13418374Skarels #define satosin(sa) ((struct sockaddr_in *)(sa)) 13518374Skarels if (sin->sin_addr.s_addr == INADDR_ANY) 13618655Skarels sin->sin_addr = IA_SIN(in_ifaddr)->sin_addr; 13724807Skarels else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST && 13818655Skarels (in_ifaddr->ia_ifp->if_flags & IFF_BROADCAST)) 13918655Skarels sin->sin_addr = satosin(&in_ifaddr->ia_broadaddr)->sin_addr; 14018374Skarels } 14110141Ssam if (inp->inp_laddr.s_addr == INADDR_ANY) { 14227262Skarels register struct route *ro; 14327262Skarels struct ifnet *ifp; 14417271Skarels 14527262Skarels ia = (struct in_ifaddr *)0; 14627262Skarels /* 14727262Skarels * If route is known or can be allocated now, 14827262Skarels * our src addr is taken from the i/f, else punt. 14927262Skarels */ 15027262Skarels ro = &inp->inp_route; 15127262Skarels if (ro->ro_rt && 15230336Skarels (satosin(&ro->ro_dst)->sin_addr.s_addr != 15330336Skarels sin->sin_addr.s_addr || 15430336Skarels inp->inp_socket->so_options & SO_DONTROUTE)) { 15527262Skarels RTFREE(ro->ro_rt); 15627262Skarels ro->ro_rt = (struct rtentry *)0; 1576338Ssam } 15828847Skarels if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/ 15928847Skarels (ro->ro_rt == (struct rtentry *)0 || 16029826Skarels ro->ro_rt->rt_ifp == (struct ifnet *)0)) { 16127262Skarels /* No route yet, so try to acquire one */ 16227262Skarels ro->ro_dst.sa_family = AF_INET; 16337471Ssklower ro->ro_dst.sa_len = sizeof(struct sockaddr_in); 16427262Skarels ((struct sockaddr_in *) &ro->ro_dst)->sin_addr = 16527262Skarels sin->sin_addr; 16627262Skarels rtalloc(ro); 16727262Skarels } 16829826Skarels /* 16929826Skarels * If we found a route, use the address 17029826Skarels * corresponding to the outgoing interface 17129826Skarels * unless it is the loopback (in case a route 17229826Skarels * to our address on another net goes to loopback). 17329826Skarels */ 17429826Skarels if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp) && 17529826Skarels (ifp->if_flags & IFF_LOOPBACK) == 0) 17629826Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 17729826Skarels if (ia->ia_ifp == ifp) 17829826Skarels break; 17928847Skarels if (ia == 0) { 18030336Skarels int fport = sin->sin_port; 18130336Skarels 18230336Skarels sin->sin_port = 0; 18328847Skarels ia = (struct in_ifaddr *) 18428847Skarels ifa_ifwithdstaddr((struct sockaddr *)sin); 18530336Skarels sin->sin_port = fport; 18628847Skarels if (ia == 0) 18728847Skarels ia = in_iaonnetof(in_netof(sin->sin_addr)); 18828847Skarels if (ia == 0) 18928847Skarels ia = in_ifaddr; 19028847Skarels if (ia == 0) 19128847Skarels return (EADDRNOTAVAIL); 19227262Skarels } 19318374Skarels ifaddr = (struct sockaddr_in *)&ia->ia_addr; 1945994Swnj } 1955994Swnj if (in_pcblookup(inp->inp_head, 1966116Swnj sin->sin_addr, 1976116Swnj sin->sin_port, 1986338Ssam inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr, 1996116Swnj inp->inp_lport, 2006116Swnj 0)) 2015172Swnj return (EADDRINUSE); 20214146Ssam if (inp->inp_laddr.s_addr == INADDR_ANY) { 20314146Ssam if (inp->inp_lport == 0) 20426382Skarels (void)in_pcbbind(inp, (struct mbuf *)0); 2056338Ssam inp->inp_laddr = ifaddr->sin_addr; 20614146Ssam } 2074951Swnj inp->inp_faddr = sin->sin_addr; 2084951Swnj inp->inp_fport = sin->sin_port; 2094923Swnj return (0); 2104923Swnj } 2114923Swnj 2125161Swnj in_pcbdisconnect(inp) 2134905Swnj struct inpcb *inp; 2144905Swnj { 2155161Swnj 21610141Ssam inp->inp_faddr.s_addr = INADDR_ANY; 2176028Sroot inp->inp_fport = 0; 2187506Sroot if (inp->inp_socket->so_state & SS_NOFDREF) 2195161Swnj in_pcbdetach(inp); 2205161Swnj } 2215161Swnj 2225161Swnj in_pcbdetach(inp) 2235161Swnj struct inpcb *inp; 2245161Swnj { 2254905Swnj struct socket *so = inp->inp_socket; 2264905Swnj 2275009Swnj so->so_pcb = 0; 2285009Swnj sofree(so); 22924807Skarels if (inp->inp_options) 23026382Skarels (void)m_free(inp->inp_options); 2316350Ssam if (inp->inp_route.ro_rt) 2326367Ssam rtfree(inp->inp_route.ro_rt); 2334983Swnj remque(inp); 2344907Swnj (void) m_free(dtom(inp)); 2354905Swnj } 2364905Swnj 2378270Sroot in_setsockaddr(inp, nam) 2386509Ssam register struct inpcb *inp; 2398270Sroot struct mbuf *nam; 2406509Ssam { 24132071Skarels register struct sockaddr_in *sin; 2428270Sroot 2438270Sroot nam->m_len = sizeof (*sin); 2448270Sroot sin = mtod(nam, struct sockaddr_in *); 2456509Ssam bzero((caddr_t)sin, sizeof (*sin)); 2466509Ssam sin->sin_family = AF_INET; 24737471Ssklower sin->sin_len = sizeof(*sin); 2486509Ssam sin->sin_port = inp->inp_lport; 2496509Ssam sin->sin_addr = inp->inp_laddr; 2506509Ssam } 2516509Ssam 25214123Ssam in_setpeeraddr(inp, nam) 25331976Skarels struct inpcb *inp; 25414123Ssam struct mbuf *nam; 25514123Ssam { 25632071Skarels register struct sockaddr_in *sin; 25714123Ssam 25814123Ssam nam->m_len = sizeof (*sin); 25914123Ssam sin = mtod(nam, struct sockaddr_in *); 26014123Ssam bzero((caddr_t)sin, sizeof (*sin)); 26114123Ssam sin->sin_family = AF_INET; 26237471Ssklower sin->sin_len = sizeof(*sin); 26314123Ssam sin->sin_port = inp->inp_fport; 26414123Ssam sin->sin_addr = inp->inp_faddr; 26514123Ssam } 26614123Ssam 2675161Swnj /* 26817357Skarels * Pass some notification to all connections of a protocol 26940692Skarels * associated with address dst. The local address and/or port numbers 27040692Skarels * may be specified to limit the search. The "usual action" will be 27140692Skarels * taken, depending on the ctlinput cmd. The caller must filter any 27240692Skarels * cmds that are uninteresting (e.g., no error in the map). 27340692Skarels * Call the protocol specific routine (if any) to report 27440692Skarels * any errors for each matching socket. 27540692Skarels * 27640692Skarels * Must be called at splnet. 2776583Ssam */ 27840692Skarels in_pcbnotify(head, dst, fport, laddr, lport, cmd, notify) 2796583Ssam struct inpcb *head; 28040692Skarels struct sockaddr *dst; 28140692Skarels u_short fport, lport; 28240692Skarels struct in_addr laddr; 28340692Skarels int cmd, (*notify)(); 2846583Ssam { 2856583Ssam register struct inpcb *inp, *oinp; 28640692Skarels struct in_addr faddr; 28740692Skarels int errno; 28840692Skarels int in_rtchange(); 28940692Skarels extern u_char inetctlerrmap[]; 2906583Ssam 29140692Skarels if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET) 29240692Skarels return; 29340692Skarels faddr = ((struct sockaddr_in *)dst)->sin_addr; 29440692Skarels if (faddr.s_addr == INADDR_ANY) 29540692Skarels return; 29640692Skarels 29740692Skarels /* 29840692Skarels * Redirects go to all references to the destination, 29940692Skarels * and use in_rtchange to invalidate the route cache. 30040692Skarels * Dead host indications: notify all references to the destination. 30140692Skarels * Otherwise, if we have knowledge of the local port and address, 30240692Skarels * deliver only to that socket. 30340692Skarels */ 30440692Skarels if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) { 30540692Skarels fport = 0; 30640692Skarels lport = 0; 30740692Skarels laddr.s_addr = 0; 30840692Skarels if (cmd != PRC_HOSTDEAD) 30940692Skarels notify = in_rtchange; 31040692Skarels } 31140692Skarels errno = inetctlerrmap[cmd]; 3126583Ssam for (inp = head->inp_next; inp != head;) { 31340692Skarels if (inp->inp_faddr.s_addr != faddr.s_addr || 31440692Skarels inp->inp_socket == 0 || 31540692Skarels (lport && inp->inp_lport != lport) || 31640692Skarels (laddr.s_addr && inp->inp_laddr.s_addr != laddr.s_addr) || 31740692Skarels (fport && inp->inp_fport != fport)) { 3186583Ssam inp = inp->inp_next; 3196583Ssam continue; 3206583Ssam } 3216583Ssam oinp = inp; 3226583Ssam inp = inp->inp_next; 32324807Skarels if (notify) 32444381Skarels (*notify)(oinp, errno); 3256583Ssam } 3266583Ssam } 3276583Ssam 32817357Skarels /* 32925508Skarels * Check for alternatives when higher level complains 33025508Skarels * about service problems. For now, invalidate cached 33125508Skarels * routing information. If the route was created dynamically 33225508Skarels * (by a redirect), time to try a default gateway again. 33325508Skarels */ 33425508Skarels in_losing(inp) 33525508Skarels struct inpcb *inp; 33625508Skarels { 33725508Skarels register struct rtentry *rt; 33825508Skarels 33925508Skarels if ((rt = inp->inp_route.ro_rt)) { 34037471Ssklower rt_missmsg(RTM_LOSING, &inp->inp_route.ro_dst, 34137471Ssklower rt->rt_gateway, (struct sockaddr *)rt_mask(rt), 34237471Ssklower (struct sockaddr *)0, rt->rt_flags, 0); 34325508Skarels if (rt->rt_flags & RTF_DYNAMIC) 34437471Ssklower (void) rtrequest(RTM_DELETE, rt_key(rt), 34537471Ssklower rt->rt_gateway, rt_mask(rt), rt->rt_flags, 34637471Ssklower (struct rtentry **)0); 34737471Ssklower inp->inp_route.ro_rt = 0; 34825508Skarels rtfree(rt); 34925508Skarels /* 35025508Skarels * A new route can be allocated 35125508Skarels * the next time output is attempted. 35225508Skarels */ 35325508Skarels } 35425508Skarels } 35525508Skarels 35625508Skarels /* 35717357Skarels * After a routing change, flush old routing 35817357Skarels * and allocate a (hopefully) better one. 35917357Skarels */ 36017357Skarels in_rtchange(inp) 36125508Skarels register struct inpcb *inp; 36217357Skarels { 36317357Skarels if (inp->inp_route.ro_rt) { 36417357Skarels rtfree(inp->inp_route.ro_rt); 36517357Skarels inp->inp_route.ro_rt = 0; 36617357Skarels /* 36717357Skarels * A new route can be allocated the next time 36817357Skarels * output is attempted. 36917357Skarels */ 37017357Skarels } 37117357Skarels } 37217357Skarels 3734907Swnj struct inpcb * 3746028Sroot in_pcblookup(head, faddr, fport, laddr, lport, flags) 3754905Swnj struct inpcb *head; 3764951Swnj struct in_addr faddr, laddr; 3774905Swnj u_short fport, lport; 3786028Sroot int flags; 3794905Swnj { 3805994Swnj register struct inpcb *inp, *match = 0; 3815994Swnj int matchwild = 3, wildcard; 3824905Swnj 3835161Swnj for (inp = head->inp_next; inp != head; inp = inp->inp_next) { 3845994Swnj if (inp->inp_lport != lport) 3855161Swnj continue; 3865994Swnj wildcard = 0; 38710141Ssam if (inp->inp_laddr.s_addr != INADDR_ANY) { 38810141Ssam if (laddr.s_addr == INADDR_ANY) 3896116Swnj wildcard++; 3906116Swnj else if (inp->inp_laddr.s_addr != laddr.s_addr) 3915994Swnj continue; 3925994Swnj } else { 39310141Ssam if (laddr.s_addr != INADDR_ANY) 3945994Swnj wildcard++; 3955994Swnj } 39610141Ssam if (inp->inp_faddr.s_addr != INADDR_ANY) { 39710141Ssam if (faddr.s_addr == INADDR_ANY) 3986116Swnj wildcard++; 3996116Swnj else if (inp->inp_faddr.s_addr != faddr.s_addr || 4006028Sroot inp->inp_fport != fport) 4015994Swnj continue; 4025994Swnj } else { 40310141Ssam if (faddr.s_addr != INADDR_ANY) 4045994Swnj wildcard++; 4055994Swnj } 4066028Sroot if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0) 4075994Swnj continue; 4085994Swnj if (wildcard < matchwild) { 4095161Swnj match = inp; 4105994Swnj matchwild = wildcard; 4115994Swnj if (matchwild == 0) 4125994Swnj break; 4135161Swnj } 4145161Swnj } 4155161Swnj return (match); 4164905Swnj } 417