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*52555Ssklower * @(#)in_pcb.c 7.16 (Berkeley) 02/18/92 823177Smckusick */ 94905Swnj 1017058Sbloom #include "param.h" 1117058Sbloom #include "systm.h" 12*52555Ssklower #include "proc.h" 1335794Skarels #include "malloc.h" 1417058Sbloom #include "mbuf.h" 1548464Skarels #include "protosw.h" 1617058Sbloom #include "socket.h" 1717058Sbloom #include "socketvar.h" 1825508Skarels #include "ioctl.h" 1951270Ssklower #include "errno.h" 2048464Skarels 2140692Skarels #include "../net/if.h" 2240692Skarels #include "../net/route.h" 2348464Skarels 2417058Sbloom #include "in.h" 2517058Sbloom #include "in_systm.h" 2640692Skarels #include "ip.h" 2717058Sbloom #include "in_pcb.h" 2818374Skarels #include "in_var.h" 294905Swnj 305240Sroot struct in_addr zeroin_addr; 315161Swnj 327506Sroot in_pcballoc(so, head) 337506Sroot struct socket *so; 347506Sroot struct inpcb *head; 357506Sroot { 367506Sroot struct mbuf *m; 377506Sroot register struct inpcb *inp; 387506Sroot 399639Ssam m = m_getclr(M_DONTWAIT, MT_PCB); 4010141Ssam if (m == NULL) 417506Sroot return (ENOBUFS); 427506Sroot inp = mtod(m, struct inpcb *); 437506Sroot inp->inp_head = head; 447506Sroot inp->inp_socket = so; 457506Sroot insque(inp, head); 467506Sroot so->so_pcb = (caddr_t)inp; 477506Sroot return (0); 487506Sroot } 497506Sroot 508270Sroot in_pcbbind(inp, nam) 517506Sroot register struct inpcb *inp; 528270Sroot struct mbuf *nam; 537506Sroot { 547506Sroot register struct socket *so = inp->inp_socket; 557506Sroot register struct inpcb *head = inp->inp_head; 568270Sroot register struct sockaddr_in *sin; 577506Sroot u_short lport = 0; 587506Sroot 5918374Skarels if (in_ifaddr == 0) 607506Sroot return (EADDRNOTAVAIL); 6110141Ssam if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY) 628270Sroot return (EINVAL); 638270Sroot if (nam == 0) 648270Sroot goto noname; 658270Sroot sin = mtod(nam, struct sockaddr_in *); 668270Sroot if (nam->m_len != sizeof (*sin)) 678270Sroot return (EINVAL); 6810141Ssam if (sin->sin_addr.s_addr != INADDR_ANY) { 698270Sroot int tport = sin->sin_port; 707506Sroot 718270Sroot sin->sin_port = 0; /* yech... */ 7218374Skarels if (ifa_ifwithaddr((struct sockaddr *)sin) == 0) 738270Sroot return (EADDRNOTAVAIL); 748270Sroot sin->sin_port = tport; 757506Sroot } 768270Sroot lport = sin->sin_port; 778270Sroot if (lport) { 7817429Skarels u_short aport = ntohs(lport); 798270Sroot int wild = 0; 807506Sroot 818270Sroot /* GROSS */ 8248464Skarels if (aport < IPPORT_RESERVED && (so->so_state & SS_PRIV) == 0) 838270Sroot return (EACCES); 8410598Ssam /* even GROSSER, but this is the Internet */ 8510598Ssam if ((so->so_options & SO_REUSEADDR) == 0 && 8610598Ssam ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 || 8710598Ssam (so->so_options & SO_ACCEPTCONN) == 0)) 888270Sroot wild = INPLOOKUP_WILDCARD; 898270Sroot if (in_pcblookup(head, 908270Sroot zeroin_addr, 0, sin->sin_addr, lport, wild)) 918270Sroot return (EADDRINUSE); 924951Swnj } 938270Sroot inp->inp_laddr = sin->sin_addr; 948270Sroot noname: 955172Swnj if (lport == 0) 965172Swnj do { 9726025Skarels if (head->inp_lport++ < IPPORT_RESERVED || 9826025Skarels head->inp_lport > IPPORT_USERRESERVED) 995994Swnj head->inp_lport = IPPORT_RESERVED; 1005172Swnj lport = htons(head->inp_lport); 1015994Swnj } while (in_pcblookup(head, 1025994Swnj zeroin_addr, 0, inp->inp_laddr, lport, 0)); 1035172Swnj inp->inp_lport = lport; 1044951Swnj return (0); 1054905Swnj } 1064905Swnj 1076116Swnj /* 1086116Swnj * Connect from a socket to a specified address. 1096116Swnj * Both address and port must be specified in argument sin. 1106116Swnj * If don't have a local address for this socket yet, 1116116Swnj * then pick one. 1126116Swnj */ 1138270Sroot in_pcbconnect(inp, nam) 11431976Skarels register struct inpcb *inp; 1158270Sroot struct mbuf *nam; 1164923Swnj { 11718374Skarels struct in_ifaddr *ia; 1186338Ssam struct sockaddr_in *ifaddr; 1198270Sroot register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); 1204923Swnj 1218270Sroot if (nam->m_len != sizeof (*sin)) 1228270Sroot return (EINVAL); 1234951Swnj if (sin->sin_family != AF_INET) 1244951Swnj return (EAFNOSUPPORT); 12518374Skarels if (sin->sin_port == 0) 1264951Swnj return (EADDRNOTAVAIL); 12718374Skarels if (in_ifaddr) { 12818655Skarels /* 12918655Skarels * If the destination address is INADDR_ANY, 13018655Skarels * use the primary local address. 13118655Skarels * If the supplied address is INADDR_BROADCAST, 13218655Skarels * and the primary interface supports broadcast, 13318655Skarels * choose the broadcast address for that interface. 13418655Skarels */ 13518374Skarels #define satosin(sa) ((struct sockaddr_in *)(sa)) 13618374Skarels if (sin->sin_addr.s_addr == INADDR_ANY) 13718655Skarels sin->sin_addr = IA_SIN(in_ifaddr)->sin_addr; 13824807Skarels else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST && 13918655Skarels (in_ifaddr->ia_ifp->if_flags & IFF_BROADCAST)) 14018655Skarels sin->sin_addr = satosin(&in_ifaddr->ia_broadaddr)->sin_addr; 14118374Skarels } 14210141Ssam if (inp->inp_laddr.s_addr == INADDR_ANY) { 14327262Skarels register struct route *ro; 14427262Skarels struct ifnet *ifp; 14517271Skarels 14627262Skarels ia = (struct in_ifaddr *)0; 14727262Skarels /* 14827262Skarels * If route is known or can be allocated now, 14927262Skarels * our src addr is taken from the i/f, else punt. 15027262Skarels */ 15127262Skarels ro = &inp->inp_route; 15227262Skarels if (ro->ro_rt && 15330336Skarels (satosin(&ro->ro_dst)->sin_addr.s_addr != 15430336Skarels sin->sin_addr.s_addr || 15530336Skarels inp->inp_socket->so_options & SO_DONTROUTE)) { 15627262Skarels RTFREE(ro->ro_rt); 15727262Skarels ro->ro_rt = (struct rtentry *)0; 1586338Ssam } 15928847Skarels if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/ 16028847Skarels (ro->ro_rt == (struct rtentry *)0 || 16129826Skarels ro->ro_rt->rt_ifp == (struct ifnet *)0)) { 16227262Skarels /* No route yet, so try to acquire one */ 16327262Skarels ro->ro_dst.sa_family = AF_INET; 16437471Ssklower ro->ro_dst.sa_len = sizeof(struct sockaddr_in); 16527262Skarels ((struct sockaddr_in *) &ro->ro_dst)->sin_addr = 16627262Skarels sin->sin_addr; 16727262Skarels rtalloc(ro); 16827262Skarels } 16929826Skarels /* 17029826Skarels * If we found a route, use the address 17129826Skarels * corresponding to the outgoing interface 17229826Skarels * unless it is the loopback (in case a route 17329826Skarels * to our address on another net goes to loopback). 17429826Skarels */ 17529826Skarels if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp) && 17629826Skarels (ifp->if_flags & IFF_LOOPBACK) == 0) 17729826Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 17829826Skarels if (ia->ia_ifp == ifp) 17929826Skarels break; 18028847Skarels if (ia == 0) { 18130336Skarels int fport = sin->sin_port; 18230336Skarels 18330336Skarels sin->sin_port = 0; 18428847Skarels ia = (struct in_ifaddr *) 18528847Skarels ifa_ifwithdstaddr((struct sockaddr *)sin); 18630336Skarels sin->sin_port = fport; 18728847Skarels if (ia == 0) 18828847Skarels ia = in_iaonnetof(in_netof(sin->sin_addr)); 18928847Skarels if (ia == 0) 19028847Skarels ia = in_ifaddr; 19128847Skarels if (ia == 0) 19228847Skarels return (EADDRNOTAVAIL); 19327262Skarels } 19418374Skarels ifaddr = (struct sockaddr_in *)&ia->ia_addr; 1955994Swnj } 1965994Swnj if (in_pcblookup(inp->inp_head, 1976116Swnj sin->sin_addr, 1986116Swnj sin->sin_port, 1996338Ssam inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr, 2006116Swnj inp->inp_lport, 2016116Swnj 0)) 2025172Swnj return (EADDRINUSE); 20314146Ssam if (inp->inp_laddr.s_addr == INADDR_ANY) { 20414146Ssam if (inp->inp_lport == 0) 20526382Skarels (void)in_pcbbind(inp, (struct mbuf *)0); 2066338Ssam inp->inp_laddr = ifaddr->sin_addr; 20714146Ssam } 2084951Swnj inp->inp_faddr = sin->sin_addr; 2094951Swnj inp->inp_fport = sin->sin_port; 2104923Swnj return (0); 2114923Swnj } 2124923Swnj 2135161Swnj in_pcbdisconnect(inp) 2144905Swnj struct inpcb *inp; 2154905Swnj { 2165161Swnj 21710141Ssam inp->inp_faddr.s_addr = INADDR_ANY; 2186028Sroot inp->inp_fport = 0; 2197506Sroot if (inp->inp_socket->so_state & SS_NOFDREF) 2205161Swnj in_pcbdetach(inp); 2215161Swnj } 2225161Swnj 2235161Swnj in_pcbdetach(inp) 2245161Swnj struct inpcb *inp; 2255161Swnj { 2264905Swnj struct socket *so = inp->inp_socket; 2274905Swnj 2285009Swnj so->so_pcb = 0; 2295009Swnj sofree(so); 23024807Skarels if (inp->inp_options) 23126382Skarels (void)m_free(inp->inp_options); 2326350Ssam if (inp->inp_route.ro_rt) 2336367Ssam rtfree(inp->inp_route.ro_rt); 2344983Swnj remque(inp); 2354907Swnj (void) m_free(dtom(inp)); 2364905Swnj } 2374905Swnj 2388270Sroot in_setsockaddr(inp, nam) 2396509Ssam register struct inpcb *inp; 2408270Sroot struct mbuf *nam; 2416509Ssam { 24232071Skarels register struct sockaddr_in *sin; 2438270Sroot 2448270Sroot nam->m_len = sizeof (*sin); 2458270Sroot sin = mtod(nam, struct sockaddr_in *); 2466509Ssam bzero((caddr_t)sin, sizeof (*sin)); 2476509Ssam sin->sin_family = AF_INET; 24837471Ssklower sin->sin_len = sizeof(*sin); 2496509Ssam sin->sin_port = inp->inp_lport; 2506509Ssam sin->sin_addr = inp->inp_laddr; 2516509Ssam } 2526509Ssam 25314123Ssam in_setpeeraddr(inp, nam) 25431976Skarels struct inpcb *inp; 25514123Ssam struct mbuf *nam; 25614123Ssam { 25732071Skarels register struct sockaddr_in *sin; 25814123Ssam 25914123Ssam nam->m_len = sizeof (*sin); 26014123Ssam sin = mtod(nam, struct sockaddr_in *); 26114123Ssam bzero((caddr_t)sin, sizeof (*sin)); 26214123Ssam sin->sin_family = AF_INET; 26337471Ssklower sin->sin_len = sizeof(*sin); 26414123Ssam sin->sin_port = inp->inp_fport; 26514123Ssam sin->sin_addr = inp->inp_faddr; 26614123Ssam } 26714123Ssam 2685161Swnj /* 26917357Skarels * Pass some notification to all connections of a protocol 27040692Skarels * associated with address dst. The local address and/or port numbers 27140692Skarels * may be specified to limit the search. The "usual action" will be 27240692Skarels * taken, depending on the ctlinput cmd. The caller must filter any 27340692Skarels * cmds that are uninteresting (e.g., no error in the map). 27440692Skarels * Call the protocol specific routine (if any) to report 27540692Skarels * any errors for each matching socket. 27640692Skarels * 27740692Skarels * Must be called at splnet. 2786583Ssam */ 27940692Skarels in_pcbnotify(head, dst, fport, laddr, lport, cmd, notify) 2806583Ssam struct inpcb *head; 28140692Skarels struct sockaddr *dst; 28240692Skarels u_short fport, lport; 28340692Skarels struct in_addr laddr; 28440692Skarels int cmd, (*notify)(); 2856583Ssam { 2866583Ssam register struct inpcb *inp, *oinp; 28740692Skarels struct in_addr faddr; 28840692Skarels int errno; 28940692Skarels int in_rtchange(); 29040692Skarels extern u_char inetctlerrmap[]; 2916583Ssam 29240692Skarels if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET) 29340692Skarels return; 29440692Skarels faddr = ((struct sockaddr_in *)dst)->sin_addr; 29540692Skarels if (faddr.s_addr == INADDR_ANY) 29640692Skarels return; 29740692Skarels 29840692Skarels /* 29940692Skarels * Redirects go to all references to the destination, 30040692Skarels * and use in_rtchange to invalidate the route cache. 30140692Skarels * Dead host indications: notify all references to the destination. 30240692Skarels * Otherwise, if we have knowledge of the local port and address, 30340692Skarels * deliver only to that socket. 30440692Skarels */ 30540692Skarels if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) { 30640692Skarels fport = 0; 30740692Skarels lport = 0; 30840692Skarels laddr.s_addr = 0; 30940692Skarels if (cmd != PRC_HOSTDEAD) 31040692Skarels notify = in_rtchange; 31140692Skarels } 31240692Skarels errno = inetctlerrmap[cmd]; 3136583Ssam for (inp = head->inp_next; inp != head;) { 31440692Skarels if (inp->inp_faddr.s_addr != faddr.s_addr || 31540692Skarels inp->inp_socket == 0 || 31640692Skarels (lport && inp->inp_lport != lport) || 31740692Skarels (laddr.s_addr && inp->inp_laddr.s_addr != laddr.s_addr) || 31840692Skarels (fport && inp->inp_fport != fport)) { 3196583Ssam inp = inp->inp_next; 3206583Ssam continue; 3216583Ssam } 3226583Ssam oinp = inp; 3236583Ssam inp = inp->inp_next; 32424807Skarels if (notify) 32544381Skarels (*notify)(oinp, errno); 3266583Ssam } 3276583Ssam } 3286583Ssam 32917357Skarels /* 33025508Skarels * Check for alternatives when higher level complains 33125508Skarels * about service problems. For now, invalidate cached 33225508Skarels * routing information. If the route was created dynamically 33325508Skarels * (by a redirect), time to try a default gateway again. 33425508Skarels */ 33525508Skarels in_losing(inp) 33625508Skarels struct inpcb *inp; 33725508Skarels { 33825508Skarels register struct rtentry *rt; 339*52555Ssklower struct rt_addrinfo info; 34025508Skarels 34125508Skarels if ((rt = inp->inp_route.ro_rt)) { 342*52555Ssklower bzero((caddr_t)&info, sizeof(info)); 343*52555Ssklower info.rti_info[RTAX_DST] = 344*52555Ssklower (struct sockaddr *)&inp->inp_route.ro_dst; 345*52555Ssklower info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; 346*52555Ssklower info.rti_info[RTAX_NETMASK] = rt_mask(rt); 347*52555Ssklower rt_missmsg(RTM_LOSING, &info, rt->rt_flags, 0); 34825508Skarels if (rt->rt_flags & RTF_DYNAMIC) 34937471Ssklower (void) rtrequest(RTM_DELETE, rt_key(rt), 35037471Ssklower rt->rt_gateway, rt_mask(rt), rt->rt_flags, 35137471Ssklower (struct rtentry **)0); 35237471Ssklower inp->inp_route.ro_rt = 0; 35325508Skarels rtfree(rt); 35425508Skarels /* 35525508Skarels * A new route can be allocated 35625508Skarels * the next time output is attempted. 35725508Skarels */ 35825508Skarels } 35925508Skarels } 36025508Skarels 36125508Skarels /* 36217357Skarels * After a routing change, flush old routing 36317357Skarels * and allocate a (hopefully) better one. 36417357Skarels */ 36517357Skarels in_rtchange(inp) 36625508Skarels register struct inpcb *inp; 36717357Skarels { 36817357Skarels if (inp->inp_route.ro_rt) { 36917357Skarels rtfree(inp->inp_route.ro_rt); 37017357Skarels inp->inp_route.ro_rt = 0; 37117357Skarels /* 37217357Skarels * A new route can be allocated the next time 37317357Skarels * output is attempted. 37417357Skarels */ 37517357Skarels } 37617357Skarels } 37717357Skarels 3784907Swnj struct inpcb * 3796028Sroot in_pcblookup(head, faddr, fport, laddr, lport, flags) 3804905Swnj struct inpcb *head; 3814951Swnj struct in_addr faddr, laddr; 3824905Swnj u_short fport, lport; 3836028Sroot int flags; 3844905Swnj { 3855994Swnj register struct inpcb *inp, *match = 0; 3865994Swnj int matchwild = 3, wildcard; 3874905Swnj 3885161Swnj for (inp = head->inp_next; inp != head; inp = inp->inp_next) { 3895994Swnj if (inp->inp_lport != lport) 3905161Swnj continue; 3915994Swnj wildcard = 0; 39210141Ssam if (inp->inp_laddr.s_addr != INADDR_ANY) { 39310141Ssam if (laddr.s_addr == INADDR_ANY) 3946116Swnj wildcard++; 3956116Swnj else if (inp->inp_laddr.s_addr != laddr.s_addr) 3965994Swnj continue; 3975994Swnj } else { 39810141Ssam if (laddr.s_addr != INADDR_ANY) 3995994Swnj wildcard++; 4005994Swnj } 40110141Ssam if (inp->inp_faddr.s_addr != INADDR_ANY) { 40210141Ssam if (faddr.s_addr == INADDR_ANY) 4036116Swnj wildcard++; 4046116Swnj else if (inp->inp_faddr.s_addr != faddr.s_addr || 4056028Sroot inp->inp_fport != fport) 4065994Swnj continue; 4075994Swnj } else { 40810141Ssam if (faddr.s_addr != INADDR_ANY) 4095994Swnj wildcard++; 4105994Swnj } 4116028Sroot if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0) 4125994Swnj continue; 4135994Swnj if (wildcard < matchwild) { 4145161Swnj match = inp; 4155994Swnj matchwild = wildcard; 4165994Swnj if (matchwild == 0) 4175994Swnj break; 4185161Swnj } 4195161Swnj } 4205161Swnj return (match); 4214905Swnj } 422