1*5277Sroot /* in_pcb.c 4.15 81/12/21 */ 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; 624951Swnj struct ifnet *ifp; 635240Sroot u_short lport; 644905Swnj 655161Swnj COUNT(IN_PCBATTACH); 664951Swnj if (sin) { 674951Swnj if (sin->sin_family != AF_INET) 684951Swnj return (EAFNOSUPPORT); 695259Swnj if (ifnet && sin->sin_addr.s_addr == 0) 705259Swnj sin->sin_addr = ifnet->if_addr; 714951Swnj ifp = if_ifwithaddr(sin->sin_addr); 724951Swnj lport = sin->sin_port; 735172Swnj if (lport && 745240Sroot in_pcblookup(head, zeroin_addr, 0, sin->sin_addr, lport)) 755172Swnj return (EADDRINUSE); 764951Swnj } else { 775259Swnj ifp = ifnet; 784951Swnj lport = 0; 794951Swnj } 805259Swnj if (ifp == 0) 815259Swnj return (EADDRNOTAVAIL); 825172Swnj m = m_getclr(0); 834951Swnj if (m == 0) 844983Swnj return (ENOBUFS); 854951Swnj if (sbreserve(&so->so_snd, sndcc) == 0) 864951Swnj goto bad; 874951Swnj if (sbreserve(&so->so_rcv, rcvcc) == 0) 884951Swnj goto bad2; 894951Swnj inp = mtod(m, struct inpcb *); 905172Swnj inp->inp_head = head; 914951Swnj inp->inp_laddr = ifp->if_addr; 925172Swnj if (lport == 0) 935172Swnj do { 945172Swnj if (head->inp_lport++ < 1024) 955172Swnj head->inp_lport = 1024; 965172Swnj lport = htons(head->inp_lport); 975240Sroot } while (in_pcblookup(head, zeroin_addr, 0, inp->inp_laddr, lport)); 985172Swnj inp->inp_lport = lport; 994983Swnj inp->inp_socket = so; 1004983Swnj insque(inp, head); 1014951Swnj so->so_pcb = (caddr_t)inp; 1024958Swnj sin = (struct sockaddr_in *)&so->so_addr; 1034958Swnj sin->sin_family = AF_INET; 1044958Swnj sin->sin_addr = inp->inp_laddr; 1054958Swnj sin->sin_port = inp->inp_lport; 1064951Swnj return (0); 1074951Swnj bad2: 1084951Swnj sbrelease(&so->so_snd); 1094951Swnj bad: 1104967Swnj (void) m_free(m); 1114951Swnj return (ENOBUFS); 1124905Swnj } 1134905Swnj 1145161Swnj in_pcbconnect(inp, sin) 1154951Swnj struct inpcb *inp; 1164951Swnj struct sockaddr_in *sin; 1174923Swnj { 1185172Swnj struct inpcb *xp; 1194923Swnj 1205161Swnj COUNT(IN_PCBCONNECT); 1214951Swnj if (sin->sin_family != AF_INET) 1224951Swnj return (EAFNOSUPPORT); 1234951Swnj if (sin->sin_addr.s_addr == 0 || sin->sin_port == 0) 1244951Swnj return (EADDRNOTAVAIL); 1255172Swnj xp = in_pcblookup(inp->inp_head, sin->sin_addr, sin->sin_port, inp->inp_laddr, inp->inp_lport); 1265240Sroot if (xp->inp_faddr.s_addr) 1275172Swnj return (EADDRINUSE); 1284951Swnj inp->inp_faddr = sin->sin_addr; 1294951Swnj inp->inp_fport = sin->sin_port; 1304923Swnj return (0); 1314923Swnj } 1324923Swnj 133*5277Sroot in_pcbconnaddr(inp, sp) 134*5277Sroot struct inpcb *inp; 135*5277Sroot struct sockaddr *sp; 136*5277Sroot { 137*5277Sroot register struct sockaddr_in *sin = (struct sockaddr_in *)sp; 138*5277Sroot 139*5277Sroot sin->sin_family = AF_INET; 140*5277Sroot sin->sin_port = inp->inp_fport; 141*5277Sroot sin->sin_addr = inp->inp_faddr; 142*5277Sroot } 143*5277Sroot 1445161Swnj in_pcbdisconnect(inp) 1454905Swnj struct inpcb *inp; 1464905Swnj { 1475161Swnj 1485161Swnj COUNT(IN_PCBDISCONNECT); 1495161Swnj inp->inp_faddr.s_addr = 0; 1505161Swnj if (inp->inp_socket->so_state & SS_USERGONE) 1515161Swnj in_pcbdetach(inp); 1525161Swnj } 1535161Swnj 1545161Swnj in_pcbdetach(inp) 1555161Swnj struct inpcb *inp; 1565161Swnj { 1574905Swnj struct socket *so = inp->inp_socket; 1584905Swnj 1595009Swnj so->so_pcb = 0; 1605009Swnj sofree(so); 1614983Swnj remque(inp); 1624907Swnj (void) m_free(dtom(inp)); 1634905Swnj } 1644905Swnj 1655161Swnj /* 1665161Swnj * Look for a control block to accept a segment. 1675161Swnj * First choice is an exact address match. 1685161Swnj * Second choice is a match of local address, with 1695161Swnj * unspecified foreign address. 1705161Swnj */ 1714907Swnj struct inpcb * 1724951Swnj in_pcblookup(head, faddr, fport, laddr, lport) 1734905Swnj struct inpcb *head; 1744951Swnj struct in_addr faddr, laddr; 1754905Swnj u_short fport, lport; 1764905Swnj { 1774905Swnj register struct inpcb *inp; 1785161Swnj struct inpcb *match = 0; 1794905Swnj 1805161Swnj for (inp = head->inp_next; inp != head; inp = inp->inp_next) { 1815161Swnj if (inp->inp_laddr.s_addr != laddr.s_addr || 1825161Swnj inp->inp_lport != lport) 1835161Swnj continue; 1845161Swnj if (inp->inp_faddr.s_addr == 0) { 1855161Swnj match = inp; 1865161Swnj continue; 1875161Swnj } 1884951Swnj if (inp->inp_faddr.s_addr == faddr.s_addr && 1895161Swnj inp->inp_fport == fport) 1904905Swnj return (inp); 1915161Swnj } 1925161Swnj return (match); 1934905Swnj } 194