1*5994Swnj /* in_pcb.c 4.17 82/02/27 */ 24905Swnj 34905Swnj #include "../h/param.h" 44951Swnj #include "../h/systm.h" 54951Swnj #include "../h/dir.h" 64951Swnj #include "../h/user.h" 74905Swnj #include "../h/mbuf.h" 84905Swnj #include "../h/socket.h" 94905Swnj #include "../h/socketvar.h" 105084Swnj #include "../net/in.h" 115084Swnj #include "../net/in_systm.h" 124951Swnj #include "../net/if.h" 135084Swnj #include "../net/in_pcb.h" 144905Swnj 154951Swnj /* 165161Swnj * Routines to manage internet protocol control blocks. 175161Swnj * 185161Swnj * At PRU_ATTACH time a protocol control block is allocated in 195161Swnj * in_pcballoc() and inserted on a doubly-linked list of such blocks 205161Swnj * for the protocol. A port address is either requested (and verified 215161Swnj * to not be in use) or assigned at this time. We also allocate 225161Swnj * space in the socket sockbuf structures here, although this is 235161Swnj * not a clearly correct place to put this function. 245161Swnj * 255161Swnj * A connectionless protocol will have its protocol control block 265161Swnj * removed at PRU_DETACH time, when the socket will be freed (freeing 275161Swnj * the space reserved) and the block will be removed from the list of 285161Swnj * blocks for its protocol. 295161Swnj * 305161Swnj * A connection-based protocol may be connected to a remote peer at 315161Swnj * PRU_CONNECT time through the routine in_pcbconnect(). In the normal 325161Swnj * case a PRU_DISCONNECT occurs causing a in_pcbdisconnect(). 335161Swnj * It is also possible that higher-level routines will opt out of the 345161Swnj * relationship with the connection before the connection shut down 355161Swnj * is complete. This often occurs in protocols like TCP where we must 365161Swnj * hold on to the protocol control block for a unreasonably long time 375161Swnj * after the connection is used up to avoid races in later connection 385161Swnj * establishment. To handle this we allow higher-level routines to 395161Swnj * disassociate themselves from the socket, marking it SS_USERGONE while 405161Swnj * the disconnect is in progress. We notice that this has happened 415161Swnj * when the disconnect is complete, and perform the PRU_DETACH operation, 425161Swnj * freeing the socket. 435172Swnj * 445172Swnj * TODO: 455172Swnj * use hashing 465161Swnj */ 475240Sroot struct in_addr zeroin_addr; 485161Swnj 495161Swnj /* 504951Swnj * Allocate a protocol control block, space 514951Swnj * for send and receive data, and local host information. 524951Swnj * Return error. If no error make socket point at pcb. 534951Swnj */ 545161Swnj in_pcbattach(so, head, sndcc, rcvcc, sin) 554951Swnj struct socket *so; 564951Swnj struct inpcb *head; 574951Swnj int sndcc, rcvcc; 584951Swnj struct sockaddr_in *sin; 594905Swnj { 604905Swnj struct mbuf *m; 615240Sroot register struct inpcb *inp; 62*5994Swnj u_short lport = 0; 634905Swnj 645161Swnj COUNT(IN_PCBATTACH); 65*5994Swnj if (ifnet == 0) 66*5994Swnj return (EADDRNOTAVAIL); 674951Swnj if (sin) { 684951Swnj if (sin->sin_family != AF_INET) 694951Swnj return (EAFNOSUPPORT); 70*5994Swnj if (sin->sin_addr.s_addr && 71*5994Swnj if_ifwithaddr(sin->sin_addr.s_addr) == 0) 72*5994Swnj return (EADDRNOTAVAIL); 734951Swnj lport = sin->sin_port; 74*5994Swnj if (lport) { 75*5994Swnj u_short aport = lport; 76*5994Swnj #if vax 77*5994Swnj aport = htons(aport); 78*5994Swnj #endif 79*5994Swnj /* GROSS */ 80*5994Swnj if (aport < IPPORT_RESERVED && u.u_uid != 0) 81*5994Swnj return (EPERM); 82*5994Swnj if (in_pcblookup(head, 83*5994Swnj zeroin_addr, 0, sin->sin_addr, lport, 0)) 84*5994Swnj return (EADDRINUSE); 85*5994Swnj } 864951Swnj } 875852Sroot m = m_getclr(M_DONTWAIT); 884951Swnj if (m == 0) 894983Swnj return (ENOBUFS); 904951Swnj if (sbreserve(&so->so_snd, sndcc) == 0) 914951Swnj goto bad; 924951Swnj if (sbreserve(&so->so_rcv, rcvcc) == 0) 934951Swnj goto bad2; 944951Swnj inp = mtod(m, struct inpcb *); 955172Swnj inp->inp_head = head; 96*5994Swnj if (sin) 97*5994Swnj inp->inp_laddr = sin->sin_addr; 985172Swnj if (lport == 0) 995172Swnj do { 100*5994Swnj if (head->inp_lport++ < IPPORT_RESERVED) 101*5994Swnj head->inp_lport = IPPORT_RESERVED; 1025172Swnj lport = htons(head->inp_lport); 103*5994Swnj } while (in_pcblookup(head, 104*5994Swnj zeroin_addr, 0, inp->inp_laddr, lport, 0)); 1055172Swnj inp->inp_lport = lport; 1064983Swnj inp->inp_socket = so; 1074983Swnj insque(inp, head); 1084951Swnj so->so_pcb = (caddr_t)inp; 109*5994Swnj in_setsockaddr(inp); 1104951Swnj return (0); 1114951Swnj bad2: 1124951Swnj sbrelease(&so->so_snd); 1134951Swnj bad: 1144967Swnj (void) m_free(m); 1154951Swnj return (ENOBUFS); 1164905Swnj } 1174905Swnj 1185161Swnj in_pcbconnect(inp, sin) 1194951Swnj struct inpcb *inp; 1204951Swnj struct sockaddr_in *sin; 1214923Swnj { 122*5994Swnj struct ifnet *ifp; 1234923Swnj 1245161Swnj COUNT(IN_PCBCONNECT); 1254951Swnj if (sin->sin_family != AF_INET) 1264951Swnj return (EAFNOSUPPORT); 1274951Swnj if (sin->sin_addr.s_addr == 0 || sin->sin_port == 0) 1284951Swnj return (EADDRNOTAVAIL); 129*5994Swnj if (inp->inp_laddr.s_addr == 0) { 130*5994Swnj ifp = if_ifonnetof(sin->sin_addr.s_addr); 131*5994Swnj if (ifp == 0) 132*5994Swnj ifp = ifnet; 133*5994Swnj inp->inp_laddr = ifp->if_addr; 134*5994Swnj } 135*5994Swnj if (in_pcblookup(inp->inp_head, 136*5994Swnj sin->sin_addr, sin->sin_port, inp->inp_laddr, inp->inp_lport, 0)) 1375172Swnj return (EADDRINUSE); 1384951Swnj inp->inp_faddr = sin->sin_addr; 1394951Swnj inp->inp_fport = sin->sin_port; 1404923Swnj return (0); 1414923Swnj } 1424923Swnj 143*5994Swnj in_setsockaddr(inp) 1445277Sroot struct inpcb *inp; 1455277Sroot { 146*5994Swnj register struct sockaddr_in *sin = 147*5994Swnj (struct sockaddr_in *)&inp->inp_socket->so_addr; 1485277Sroot 1495277Sroot sin->sin_family = AF_INET; 150*5994Swnj sin->sin_addr = inp->inp_laddr; 151*5994Swnj sin->sin_port = inp->inp_lport; 1525277Sroot } 1535277Sroot 1545161Swnj in_pcbdisconnect(inp) 1554905Swnj struct inpcb *inp; 1564905Swnj { 1575161Swnj 1585161Swnj COUNT(IN_PCBDISCONNECT); 1595161Swnj inp->inp_faddr.s_addr = 0; 1605161Swnj if (inp->inp_socket->so_state & SS_USERGONE) 1615161Swnj in_pcbdetach(inp); 1625161Swnj } 1635161Swnj 1645161Swnj in_pcbdetach(inp) 1655161Swnj struct inpcb *inp; 1665161Swnj { 1674905Swnj struct socket *so = inp->inp_socket; 1684905Swnj 1695009Swnj so->so_pcb = 0; 1705009Swnj sofree(so); 1714983Swnj remque(inp); 1724907Swnj (void) m_free(dtom(inp)); 1734905Swnj } 1744905Swnj 1755161Swnj /* 1765161Swnj * Look for a control block to accept a segment. 1775161Swnj * First choice is an exact address match. 178*5994Swnj * Second choice is a match with either the foreign or the local 179*5994Swnj * address specified. 180*5994Swnj * 181*5994Swnj * SHOULD ALLOW MATCH ON MULTI-HOMING ONLY 1825161Swnj */ 1834907Swnj struct inpcb * 184*5994Swnj in_pcblookup(head, faddr, fport, laddr, lport, enter) 1854905Swnj struct inpcb *head; 1864951Swnj struct in_addr faddr, laddr; 1874905Swnj u_short fport, lport; 188*5994Swnj int enter; 1894905Swnj { 190*5994Swnj register struct inpcb *inp, *match = 0; 191*5994Swnj int matchwild = 3, wildcard; 1924905Swnj 1935161Swnj for (inp = head->inp_next; inp != head; inp = inp->inp_next) { 194*5994Swnj if (inp->inp_lport != lport) 1955161Swnj continue; 196*5994Swnj wildcard = 0; 197*5994Swnj if (inp->inp_laddr.s_addr != 0) { 198*5994Swnj if (inp->inp_laddr.s_addr != laddr.s_addr) 199*5994Swnj continue; 200*5994Swnj } else { 201*5994Swnj if (laddr.s_addr != 0) 202*5994Swnj wildcard++; 203*5994Swnj } 204*5994Swnj if (inp->inp_faddr.s_addr != 0) { 205*5994Swnj if (inp->inp_faddr.s_addr != faddr.s_addr) 206*5994Swnj continue; 207*5994Swnj } else { 208*5994Swnj if (faddr.s_addr != 0) 209*5994Swnj wildcard++; 210*5994Swnj } 211*5994Swnj if (enter == 0 && wildcard) 212*5994Swnj continue; 213*5994Swnj if (wildcard < matchwild) { 2145161Swnj match = inp; 215*5994Swnj matchwild = wildcard; 216*5994Swnj if (matchwild == 0) 217*5994Swnj break; 2185161Swnj } 2195161Swnj } 220*5994Swnj if (match && enter) { 221*5994Swnj match->inp_laddr = laddr; 222*5994Swnj in_setsockaddr(match); 223*5994Swnj } 2245161Swnj return (match); 2254905Swnj } 226