123177Smckusick /* 223177Smckusick * Copyright (c) 1982 Regents of the University of California. 323177Smckusick * All rights reserved. The Berkeley software License Agreement 423177Smckusick * specifies the terms and conditions for redistribution. 523177Smckusick * 6*24807Skarels * @(#)in_pcb.c 6.9 (Berkeley) 09/16/85 723177Smckusick */ 84905Swnj 917058Sbloom #include "param.h" 1017058Sbloom #include "systm.h" 1117058Sbloom #include "dir.h" 1217058Sbloom #include "user.h" 1317058Sbloom #include "mbuf.h" 1417058Sbloom #include "socket.h" 1517058Sbloom #include "socketvar.h" 1617058Sbloom #include "in.h" 1717058Sbloom #include "in_systm.h" 184951Swnj #include "../net/if.h" 196350Ssam #include "../net/route.h" 2017058Sbloom #include "in_pcb.h" 2118374Skarels #include "in_var.h" 2217058Sbloom #include "protosw.h" 234905Swnj 245240Sroot struct in_addr zeroin_addr; 255161Swnj 267506Sroot in_pcballoc(so, head) 277506Sroot struct socket *so; 287506Sroot struct inpcb *head; 297506Sroot { 307506Sroot struct mbuf *m; 317506Sroot register struct inpcb *inp; 327506Sroot 339639Ssam m = m_getclr(M_DONTWAIT, MT_PCB); 3410141Ssam if (m == NULL) 357506Sroot return (ENOBUFS); 367506Sroot inp = mtod(m, struct inpcb *); 377506Sroot inp->inp_head = head; 387506Sroot inp->inp_socket = so; 397506Sroot insque(inp, head); 407506Sroot so->so_pcb = (caddr_t)inp; 417506Sroot return (0); 427506Sroot } 437506Sroot 448270Sroot in_pcbbind(inp, nam) 457506Sroot register struct inpcb *inp; 468270Sroot struct mbuf *nam; 477506Sroot { 487506Sroot register struct socket *so = inp->inp_socket; 497506Sroot register struct inpcb *head = inp->inp_head; 508270Sroot register struct sockaddr_in *sin; 517506Sroot u_short lport = 0; 527506Sroot 5318374Skarels if (in_ifaddr == 0) 547506Sroot return (EADDRNOTAVAIL); 5510141Ssam if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY) 568270Sroot return (EINVAL); 578270Sroot if (nam == 0) 588270Sroot goto noname; 598270Sroot sin = mtod(nam, struct sockaddr_in *); 608270Sroot if (nam->m_len != sizeof (*sin)) 618270Sroot return (EINVAL); 6210141Ssam if (sin->sin_addr.s_addr != INADDR_ANY) { 638270Sroot int tport = sin->sin_port; 647506Sroot 658270Sroot sin->sin_port = 0; /* yech... */ 6618374Skarels if (ifa_ifwithaddr((struct sockaddr *)sin) == 0) 678270Sroot return (EADDRNOTAVAIL); 688270Sroot sin->sin_port = tport; 697506Sroot } 708270Sroot lport = sin->sin_port; 718270Sroot if (lport) { 7217429Skarels u_short aport = ntohs(lport); 738270Sroot int wild = 0; 747506Sroot 758270Sroot /* GROSS */ 768270Sroot if (aport < IPPORT_RESERVED && u.u_uid != 0) 778270Sroot return (EACCES); 7810598Ssam /* even GROSSER, but this is the Internet */ 7910598Ssam if ((so->so_options & SO_REUSEADDR) == 0 && 8010598Ssam ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 || 8110598Ssam (so->so_options & SO_ACCEPTCONN) == 0)) 828270Sroot wild = INPLOOKUP_WILDCARD; 838270Sroot if (in_pcblookup(head, 848270Sroot zeroin_addr, 0, sin->sin_addr, lport, wild)) 858270Sroot return (EADDRINUSE); 864951Swnj } 878270Sroot inp->inp_laddr = sin->sin_addr; 888270Sroot noname: 895172Swnj if (lport == 0) 905172Swnj do { 915994Swnj if (head->inp_lport++ < IPPORT_RESERVED) 925994Swnj head->inp_lport = IPPORT_RESERVED; 935172Swnj lport = htons(head->inp_lport); 945994Swnj } while (in_pcblookup(head, 955994Swnj zeroin_addr, 0, inp->inp_laddr, lport, 0)); 965172Swnj inp->inp_lport = lport; 974951Swnj return (0); 984905Swnj } 994905Swnj 1006116Swnj /* 1016116Swnj * Connect from a socket to a specified address. 1026116Swnj * Both address and port must be specified in argument sin. 1036116Swnj * If don't have a local address for this socket yet, 1046116Swnj * then pick one. 1056116Swnj */ 1068270Sroot in_pcbconnect(inp, nam) 1074951Swnj struct inpcb *inp; 1088270Sroot struct mbuf *nam; 1094923Swnj { 11018374Skarels struct in_ifaddr *ia; 1116338Ssam struct sockaddr_in *ifaddr; 1128270Sroot register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); 1134923Swnj 1148270Sroot if (nam->m_len != sizeof (*sin)) 1158270Sroot return (EINVAL); 1164951Swnj if (sin->sin_family != AF_INET) 1174951Swnj return (EAFNOSUPPORT); 11818374Skarels if (sin->sin_port == 0) 1194951Swnj return (EADDRNOTAVAIL); 12018374Skarels if (in_ifaddr) { 12118655Skarels /* 12218655Skarels * If the destination address is INADDR_ANY, 12318655Skarels * use the primary local address. 12418655Skarels * If the supplied address is INADDR_BROADCAST, 12518655Skarels * and the primary interface supports broadcast, 12618655Skarels * choose the broadcast address for that interface. 12718655Skarels */ 12818374Skarels #define satosin(sa) ((struct sockaddr_in *)(sa)) 12918374Skarels if (sin->sin_addr.s_addr == INADDR_ANY) 13018655Skarels sin->sin_addr = IA_SIN(in_ifaddr)->sin_addr; 131*24807Skarels else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST && 13218655Skarels (in_ifaddr->ia_ifp->if_flags & IFF_BROADCAST)) 13318655Skarels sin->sin_addr = satosin(&in_ifaddr->ia_broadaddr)->sin_addr; 13418374Skarels } 13510141Ssam if (inp->inp_laddr.s_addr == INADDR_ANY) { 13618655Skarels ia = (struct in_ifaddr *)ifa_ifwithnet((struct sockaddr *)sin); 13718374Skarels if (ia == (struct in_ifaddr *)0) { 13817271Skarels register struct route *ro; 13918374Skarels struct ifnet *ifp; 14017271Skarels 14117271Skarels /* 14217271Skarels * If route is known or can be allocated now, 14317271Skarels * our src addr is taken from the i/f, else punt. 1446583Ssam */ 14517271Skarels ro = &inp->inp_route; 14617271Skarels if (ro->ro_rt && 14717271Skarels satosin(&ro->ro_dst)->sin_addr.s_addr != 14817271Skarels sin->sin_addr.s_addr) { 14917271Skarels RTFREE(ro->ro_rt); 15017271Skarels ro->ro_rt = (struct rtentry *)0; 15117271Skarels } 15217271Skarels if ((ro->ro_rt == (struct rtentry *)0) || 15317271Skarels (ifp = ro->ro_rt->rt_ifp) == (struct ifnet *)0) { 15417271Skarels /* No route yet, so try to acquire one */ 15517271Skarels ro->ro_dst.sa_family = AF_INET; 15617271Skarels ((struct sockaddr_in *) &ro->ro_dst)->sin_addr = 15717271Skarels sin->sin_addr; 15817271Skarels rtalloc(ro); 15917271Skarels if (ro->ro_rt == 0) 16018655Skarels ifp = (struct ifnet *)0; 16117271Skarels else 16218655Skarels ifp = ro->ro_rt->rt_ifp; 16318655Skarels } 16418655Skarels if (ifp) { 16518655Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 16618374Skarels if (ia->ia_ifp == ifp) 16718655Skarels break; 16818655Skarels } else 16918655Skarels ia = (struct in_ifaddr *)0; 17018374Skarels if (ia == 0) 17118374Skarels ia = in_ifaddr; 17218374Skarels if (ia == 0) 1736583Ssam return (EADDRNOTAVAIL); 1746338Ssam } 17518374Skarels ifaddr = (struct sockaddr_in *)&ia->ia_addr; 1765994Swnj } 1775994Swnj if (in_pcblookup(inp->inp_head, 1786116Swnj sin->sin_addr, 1796116Swnj sin->sin_port, 1806338Ssam inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr, 1816116Swnj inp->inp_lport, 1826116Swnj 0)) 1835172Swnj return (EADDRINUSE); 18414146Ssam if (inp->inp_laddr.s_addr == INADDR_ANY) { 18514146Ssam if (inp->inp_lport == 0) 18614146Ssam in_pcbbind(inp, (struct mbuf *)0); 1876338Ssam inp->inp_laddr = ifaddr->sin_addr; 18814146Ssam } 1894951Swnj inp->inp_faddr = sin->sin_addr; 1904951Swnj inp->inp_fport = sin->sin_port; 1914923Swnj return (0); 1924923Swnj } 1934923Swnj 1945161Swnj in_pcbdisconnect(inp) 1954905Swnj struct inpcb *inp; 1964905Swnj { 1975161Swnj 19810141Ssam inp->inp_faddr.s_addr = INADDR_ANY; 1996028Sroot inp->inp_fport = 0; 2007506Sroot if (inp->inp_socket->so_state & SS_NOFDREF) 2015161Swnj in_pcbdetach(inp); 2025161Swnj } 2035161Swnj 2045161Swnj in_pcbdetach(inp) 2055161Swnj struct inpcb *inp; 2065161Swnj { 2074905Swnj struct socket *so = inp->inp_socket; 2084905Swnj 2095009Swnj so->so_pcb = 0; 2105009Swnj sofree(so); 211*24807Skarels if (inp->inp_options) 212*24807Skarels m_free(inp->inp_options); 2136350Ssam if (inp->inp_route.ro_rt) 2146367Ssam rtfree(inp->inp_route.ro_rt); 2154983Swnj remque(inp); 2164907Swnj (void) m_free(dtom(inp)); 2174905Swnj } 2184905Swnj 2198270Sroot in_setsockaddr(inp, nam) 2206509Ssam register struct inpcb *inp; 2218270Sroot struct mbuf *nam; 2226509Ssam { 2238270Sroot register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); 2248270Sroot 2258270Sroot nam->m_len = sizeof (*sin); 2268270Sroot sin = mtod(nam, struct sockaddr_in *); 2276509Ssam bzero((caddr_t)sin, sizeof (*sin)); 2286509Ssam sin->sin_family = AF_INET; 2296509Ssam sin->sin_port = inp->inp_lport; 2306509Ssam sin->sin_addr = inp->inp_laddr; 2316509Ssam } 2326509Ssam 23314123Ssam in_setpeeraddr(inp, nam) 23414123Ssam register struct inpcb *inp; 23514123Ssam struct mbuf *nam; 23614123Ssam { 23714123Ssam register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); 23814123Ssam 23914123Ssam nam->m_len = sizeof (*sin); 24014123Ssam sin = mtod(nam, struct sockaddr_in *); 24114123Ssam bzero((caddr_t)sin, sizeof (*sin)); 24214123Ssam sin->sin_family = AF_INET; 24314123Ssam sin->sin_port = inp->inp_fport; 24414123Ssam sin->sin_addr = inp->inp_faddr; 24514123Ssam } 24614123Ssam 2475161Swnj /* 24817357Skarels * Pass some notification to all connections of a protocol 249*24807Skarels * associated with address dst. Call the protocol specific 250*24807Skarels * routine (if any) to handle each connection. 2516583Ssam */ 25217357Skarels in_pcbnotify(head, dst, errno, notify) 2536583Ssam struct inpcb *head; 2546583Ssam register struct in_addr *dst; 25517357Skarels int errno, (*notify)(); 2566583Ssam { 2576583Ssam register struct inpcb *inp, *oinp; 2586583Ssam int s = splimp(); 2596583Ssam 2606583Ssam for (inp = head->inp_next; inp != head;) { 261*24807Skarels if (inp->inp_faddr.s_addr != dst->s_addr || 262*24807Skarels inp->inp_socket == 0) { 2636583Ssam inp = inp->inp_next; 2646583Ssam continue; 2656583Ssam } 26617357Skarels if (errno) 26717357Skarels inp->inp_socket->so_error = errno; 2686583Ssam oinp = inp; 2696583Ssam inp = inp->inp_next; 270*24807Skarels if (notify) 271*24807Skarels (*notify)(oinp); 2726583Ssam } 2736583Ssam splx(s); 2746583Ssam } 2756583Ssam 27617357Skarels /* 27717357Skarels * After a routing change, flush old routing 27817357Skarels * and allocate a (hopefully) better one. 27917357Skarels */ 28017357Skarels in_rtchange(inp) 28117357Skarels struct inpcb *inp; 28217357Skarels { 28317357Skarels if (inp->inp_route.ro_rt) { 28417357Skarels rtfree(inp->inp_route.ro_rt); 28517357Skarels inp->inp_route.ro_rt = 0; 28617357Skarels /* 28717357Skarels * A new route can be allocated the next time 28817357Skarels * output is attempted. 28917357Skarels */ 29017357Skarels } 29117357Skarels } 29217357Skarels 2934907Swnj struct inpcb * 2946028Sroot in_pcblookup(head, faddr, fport, laddr, lport, flags) 2954905Swnj struct inpcb *head; 2964951Swnj struct in_addr faddr, laddr; 2974905Swnj u_short fport, lport; 2986028Sroot int flags; 2994905Swnj { 3005994Swnj register struct inpcb *inp, *match = 0; 3015994Swnj int matchwild = 3, wildcard; 3024905Swnj 3035161Swnj for (inp = head->inp_next; inp != head; inp = inp->inp_next) { 3045994Swnj if (inp->inp_lport != lport) 3055161Swnj continue; 3065994Swnj wildcard = 0; 30710141Ssam if (inp->inp_laddr.s_addr != INADDR_ANY) { 30810141Ssam if (laddr.s_addr == INADDR_ANY) 3096116Swnj wildcard++; 3106116Swnj else if (inp->inp_laddr.s_addr != laddr.s_addr) 3115994Swnj continue; 3125994Swnj } else { 31310141Ssam if (laddr.s_addr != INADDR_ANY) 3145994Swnj wildcard++; 3155994Swnj } 31610141Ssam if (inp->inp_faddr.s_addr != INADDR_ANY) { 31710141Ssam if (faddr.s_addr == INADDR_ANY) 3186116Swnj wildcard++; 3196116Swnj else if (inp->inp_faddr.s_addr != faddr.s_addr || 3206028Sroot inp->inp_fport != fport) 3215994Swnj continue; 3225994Swnj } else { 32310141Ssam if (faddr.s_addr != INADDR_ANY) 3245994Swnj wildcard++; 3255994Swnj } 3266028Sroot if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0) 3275994Swnj continue; 3285994Swnj if (wildcard < matchwild) { 3295161Swnj match = inp; 3305994Swnj matchwild = wildcard; 3315994Swnj if (matchwild == 0) 3325994Swnj break; 3335161Swnj } 3345161Swnj } 3355161Swnj return (match); 3364905Swnj } 337