1*18374Skarels /* in_pcb.c 6.6 85/03/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" 15*18374Skarels #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 47*18374Skarels 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... */ 60*18374Skarels 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 { 104*18374Skarels 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); 112*18374Skarels if (sin->sin_port == 0) 1134951Swnj return (EADDRNOTAVAIL); 114*18374Skarels if (in_ifaddr) { 115*18374Skarels #define satosin(sa) ((struct sockaddr_in *)(sa)) 116*18374Skarels if (sin->sin_addr.s_addr == INADDR_ANY) 117*18374Skarels sin->sin_addr.s_addr = IA_SIN(in_ifaddr)->sin_addr.s_addr; 118*18374Skarels else if (sin->sin_addr.s_addr == INADDR_BROADCAST) 119*18374Skarels /* SHOULD CHECK FOR BROADCAST CAPABILITY */ 120*18374Skarels sin->sin_addr.s_addr = satosin(&in_ifaddr->ia_broadaddr)->sin_addr.s_addr; 121*18374Skarels } 12210141Ssam if (inp->inp_laddr.s_addr == INADDR_ANY) { 123*18374Skarels ia = (struct in_ifaddr *)ifa_ifwithnet(sin); 124*18374Skarels if (ia == (struct in_ifaddr *)0) { 12517271Skarels register struct route *ro; 126*18374Skarels struct ifnet *ifp; 12717271Skarels 12817271Skarels /* 12917271Skarels * If route is known or can be allocated now, 13017271Skarels * our src addr is taken from the i/f, else punt. 1316583Ssam */ 13217271Skarels ro = &inp->inp_route; 13317271Skarels if (ro->ro_rt && 13417271Skarels satosin(&ro->ro_dst)->sin_addr.s_addr != 13517271Skarels sin->sin_addr.s_addr) { 13617271Skarels RTFREE(ro->ro_rt); 13717271Skarels ro->ro_rt = (struct rtentry *)0; 13817271Skarels } 13917271Skarels if ((ro->ro_rt == (struct rtentry *)0) || 14017271Skarels (ifp = ro->ro_rt->rt_ifp) == (struct ifnet *)0) { 141*18374Skarels struct ifnet *ifp; 142*18374Skarels 14317271Skarels /* No route yet, so try to acquire one */ 14417271Skarels ro->ro_dst.sa_family = AF_INET; 14517271Skarels ((struct sockaddr_in *) &ro->ro_dst)->sin_addr = 14617271Skarels sin->sin_addr; 14717271Skarels rtalloc(ro); 14817271Skarels if (ro->ro_rt == 0) 149*18374Skarels ia = (struct in_ifaddr *) 0; 15017271Skarels else 151*18374Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 152*18374Skarels if (ia->ia_ifp == ifp) 153*18374Skarels break; 15417271Skarels } 155*18374Skarels if (ia == 0) 156*18374Skarels ia = in_ifaddr; 157*18374Skarels if (ia == 0) 1586583Ssam return (EADDRNOTAVAIL); 1596338Ssam } 160*18374Skarels ifaddr = (struct sockaddr_in *)&ia->ia_addr; 1615994Swnj } 1625994Swnj if (in_pcblookup(inp->inp_head, 1636116Swnj sin->sin_addr, 1646116Swnj sin->sin_port, 1656338Ssam inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr, 1666116Swnj inp->inp_lport, 1676116Swnj 0)) 1685172Swnj return (EADDRINUSE); 16914146Ssam if (inp->inp_laddr.s_addr == INADDR_ANY) { 17014146Ssam if (inp->inp_lport == 0) 17114146Ssam in_pcbbind(inp, (struct mbuf *)0); 1726338Ssam inp->inp_laddr = ifaddr->sin_addr; 17314146Ssam } 1744951Swnj inp->inp_faddr = sin->sin_addr; 1754951Swnj inp->inp_fport = sin->sin_port; 1764923Swnj return (0); 1774923Swnj } 1784923Swnj 1795161Swnj in_pcbdisconnect(inp) 1804905Swnj struct inpcb *inp; 1814905Swnj { 1825161Swnj 18310141Ssam inp->inp_faddr.s_addr = INADDR_ANY; 1846028Sroot inp->inp_fport = 0; 1857506Sroot if (inp->inp_socket->so_state & SS_NOFDREF) 1865161Swnj in_pcbdetach(inp); 1875161Swnj } 1885161Swnj 1895161Swnj in_pcbdetach(inp) 1905161Swnj struct inpcb *inp; 1915161Swnj { 1924905Swnj struct socket *so = inp->inp_socket; 1934905Swnj 1945009Swnj so->so_pcb = 0; 1955009Swnj sofree(so); 1966350Ssam if (inp->inp_route.ro_rt) 1976367Ssam rtfree(inp->inp_route.ro_rt); 1984983Swnj remque(inp); 1994907Swnj (void) m_free(dtom(inp)); 2004905Swnj } 2014905Swnj 2028270Sroot in_setsockaddr(inp, nam) 2036509Ssam register struct inpcb *inp; 2048270Sroot struct mbuf *nam; 2056509Ssam { 2068270Sroot register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); 2078270Sroot 2088270Sroot nam->m_len = sizeof (*sin); 2098270Sroot sin = mtod(nam, struct sockaddr_in *); 2106509Ssam bzero((caddr_t)sin, sizeof (*sin)); 2116509Ssam sin->sin_family = AF_INET; 2126509Ssam sin->sin_port = inp->inp_lport; 2136509Ssam sin->sin_addr = inp->inp_laddr; 2146509Ssam } 2156509Ssam 21614123Ssam in_setpeeraddr(inp, nam) 21714123Ssam register struct inpcb *inp; 21814123Ssam struct mbuf *nam; 21914123Ssam { 22014123Ssam register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); 22114123Ssam 22214123Ssam nam->m_len = sizeof (*sin); 22314123Ssam sin = mtod(nam, struct sockaddr_in *); 22414123Ssam bzero((caddr_t)sin, sizeof (*sin)); 22514123Ssam sin->sin_family = AF_INET; 22614123Ssam sin->sin_port = inp->inp_fport; 22714123Ssam sin->sin_addr = inp->inp_faddr; 22814123Ssam } 22914123Ssam 2305161Swnj /* 23117357Skarels * Pass some notification to all connections of a protocol 23217357Skarels * associated with address dst. Call the 23317357Skarels * protocol specific routine to handle each connection. 2346583Ssam */ 23517357Skarels in_pcbnotify(head, dst, errno, notify) 2366583Ssam struct inpcb *head; 2376583Ssam register struct in_addr *dst; 23817357Skarels int errno, (*notify)(); 2396583Ssam { 2406583Ssam register struct inpcb *inp, *oinp; 2416583Ssam int s = splimp(); 2426583Ssam 2436583Ssam for (inp = head->inp_next; inp != head;) { 2446583Ssam if (inp->inp_faddr.s_addr != dst->s_addr) { 2456583Ssam next: 2466583Ssam inp = inp->inp_next; 2476583Ssam continue; 2486583Ssam } 2496583Ssam if (inp->inp_socket == 0) 2506583Ssam goto next; 25117357Skarels if (errno) 25217357Skarels inp->inp_socket->so_error = errno; 2536583Ssam oinp = inp; 2546583Ssam inp = inp->inp_next; 25517357Skarels (*notify)(oinp); 2566583Ssam } 2576583Ssam splx(s); 2586583Ssam } 2596583Ssam 26017357Skarels /* 26117357Skarels * After a routing change, flush old routing 26217357Skarels * and allocate a (hopefully) better one. 26317357Skarels */ 26417357Skarels in_rtchange(inp) 26517357Skarels struct inpcb *inp; 26617357Skarels { 26717357Skarels if (inp->inp_route.ro_rt) { 26817357Skarels rtfree(inp->inp_route.ro_rt); 26917357Skarels inp->inp_route.ro_rt = 0; 27017357Skarels /* 27117357Skarels * A new route can be allocated the next time 27217357Skarels * output is attempted. 27317357Skarels */ 27417357Skarels } 27517357Skarels /* SHOULD NOTIFY HIGHER-LEVEL PROTOCOLS */ 27617357Skarels } 27717357Skarels 2784907Swnj struct inpcb * 2796028Sroot in_pcblookup(head, faddr, fport, laddr, lport, flags) 2804905Swnj struct inpcb *head; 2814951Swnj struct in_addr faddr, laddr; 2824905Swnj u_short fport, lport; 2836028Sroot int flags; 2844905Swnj { 2855994Swnj register struct inpcb *inp, *match = 0; 2865994Swnj int matchwild = 3, wildcard; 2874905Swnj 2885161Swnj for (inp = head->inp_next; inp != head; inp = inp->inp_next) { 2895994Swnj if (inp->inp_lport != lport) 2905161Swnj continue; 2915994Swnj wildcard = 0; 29210141Ssam if (inp->inp_laddr.s_addr != INADDR_ANY) { 29310141Ssam if (laddr.s_addr == INADDR_ANY) 2946116Swnj wildcard++; 2956116Swnj else if (inp->inp_laddr.s_addr != laddr.s_addr) 2965994Swnj continue; 2975994Swnj } else { 29810141Ssam if (laddr.s_addr != INADDR_ANY) 2995994Swnj wildcard++; 3005994Swnj } 30110141Ssam if (inp->inp_faddr.s_addr != INADDR_ANY) { 30210141Ssam if (faddr.s_addr == INADDR_ANY) 3036116Swnj wildcard++; 3046116Swnj else if (inp->inp_faddr.s_addr != faddr.s_addr || 3056028Sroot inp->inp_fport != fport) 3065994Swnj continue; 3075994Swnj } else { 30810141Ssam if (faddr.s_addr != INADDR_ANY) 3095994Swnj wildcard++; 3105994Swnj } 3116028Sroot if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0) 3125994Swnj continue; 3135994Swnj if (wildcard < matchwild) { 3145161Swnj match = inp; 3155994Swnj matchwild = wildcard; 3165994Swnj if (matchwild == 0) 3175994Swnj break; 3185161Swnj } 3195161Swnj } 3205161Swnj return (match); 3214905Swnj } 322