1 /* in_pcb.c 4.37 82/12/14 */ 2 3 #include "../h/param.h" 4 #include "../h/systm.h" 5 #include "../h/dir.h" 6 #include "../h/user.h" 7 #include "../h/mbuf.h" 8 #include "../h/socket.h" 9 #include "../h/socketvar.h" 10 #include "../netinet/in.h" 11 #include "../netinet/in_systm.h" 12 #include "../net/if.h" 13 #include "../net/route.h" 14 #include "../netinet/in_pcb.h" 15 #include "../h/protosw.h" 16 17 struct in_addr zeroin_addr; 18 19 in_pcballoc(so, head) 20 struct socket *so; 21 struct inpcb *head; 22 { 23 struct mbuf *m; 24 register struct inpcb *inp; 25 26 m = m_getclr(M_DONTWAIT, MT_PCB); 27 if (m == 0) 28 return (ENOBUFS); 29 inp = mtod(m, struct inpcb *); 30 inp->inp_head = head; 31 inp->inp_socket = so; 32 insque(inp, head); 33 so->so_pcb = (caddr_t)inp; 34 return (0); 35 } 36 37 in_pcbbind(inp, nam) 38 register struct inpcb *inp; 39 struct mbuf *nam; 40 { 41 register struct socket *so = inp->inp_socket; 42 register struct inpcb *head = inp->inp_head; 43 register struct sockaddr_in *sin; 44 u_short lport = 0; 45 46 if (ifnet == 0) 47 return (EADDRNOTAVAIL); 48 if (inp->inp_lport || inp->inp_laddr.s_addr) 49 return (EINVAL); 50 if (nam == 0) 51 goto noname; 52 sin = mtod(nam, struct sockaddr_in *); 53 if (nam->m_len != sizeof (*sin)) 54 return (EINVAL); 55 if (sin->sin_addr.s_addr) { 56 int tport = sin->sin_port; 57 58 sin->sin_port = 0; /* yech... */ 59 if (if_ifwithaddr((struct sockaddr *)sin) == 0) 60 return (EADDRNOTAVAIL); 61 sin->sin_port = tport; 62 } 63 lport = sin->sin_port; 64 if (lport) { 65 u_short aport = htons(lport); 66 int wild = 0; 67 68 /* GROSS */ 69 if (aport < IPPORT_RESERVED && u.u_uid != 0) 70 return (EACCES); 71 if ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0) 72 wild = INPLOOKUP_WILDCARD; 73 if (in_pcblookup(head, 74 zeroin_addr, 0, sin->sin_addr, lport, wild)) 75 return (EADDRINUSE); 76 } 77 inp->inp_laddr = sin->sin_addr; 78 noname: 79 if (lport == 0) 80 do { 81 if (head->inp_lport++ < IPPORT_RESERVED) 82 head->inp_lport = IPPORT_RESERVED; 83 lport = htons(head->inp_lport); 84 } while (in_pcblookup(head, 85 zeroin_addr, 0, inp->inp_laddr, lport, 0)); 86 inp->inp_lport = lport; 87 return (0); 88 } 89 90 /* 91 * Connect from a socket to a specified address. 92 * Both address and port must be specified in argument sin. 93 * If don't have a local address for this socket yet, 94 * then pick one. 95 */ 96 in_pcbconnect(inp, nam) 97 struct inpcb *inp; 98 struct mbuf *nam; 99 { 100 struct ifnet *ifp; 101 struct sockaddr_in *ifaddr; 102 register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); 103 104 if (nam->m_len != sizeof (*sin)) 105 return (EINVAL); 106 if (sin->sin_family != AF_INET) 107 return (EAFNOSUPPORT); 108 if (sin->sin_addr.s_addr == 0 || sin->sin_port == 0) 109 return (EADDRNOTAVAIL); 110 if (inp->inp_laddr.s_addr == 0) { 111 ifp = if_ifonnetof(in_netof(sin->sin_addr)); 112 if (ifp == 0) { 113 /* 114 * We should select the interface based on 115 * the route to be used, but for udp this would 116 * result in two calls to rtalloc for each packet 117 * sent; hardly worthwhile... 118 */ 119 ifp = if_ifwithaf(AF_INET); 120 if (ifp == 0) 121 return (EADDRNOTAVAIL); 122 } 123 ifaddr = (struct sockaddr_in *)&ifp->if_addr; 124 } 125 if (in_pcblookup(inp->inp_head, 126 sin->sin_addr, 127 sin->sin_port, 128 inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr, 129 inp->inp_lport, 130 0)) 131 return (EADDRINUSE); 132 if (inp->inp_laddr.s_addr == 0) 133 inp->inp_laddr = ifaddr->sin_addr; 134 inp->inp_faddr = sin->sin_addr; 135 inp->inp_fport = sin->sin_port; 136 return (0); 137 } 138 139 in_pcbdisconnect(inp) 140 struct inpcb *inp; 141 { 142 143 inp->inp_faddr.s_addr = 0; 144 inp->inp_fport = 0; 145 if (inp->inp_socket->so_state & SS_NOFDREF) 146 in_pcbdetach(inp); 147 } 148 149 in_pcbdetach(inp) 150 struct inpcb *inp; 151 { 152 struct socket *so = inp->inp_socket; 153 154 so->so_pcb = 0; 155 sofree(so); 156 if (inp->inp_route.ro_rt) 157 rtfree(inp->inp_route.ro_rt); 158 remque(inp); 159 (void) m_free(dtom(inp)); 160 } 161 162 in_setsockaddr(inp, nam) 163 register struct inpcb *inp; 164 struct mbuf *nam; 165 { 166 register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); 167 168 nam->m_len = sizeof (*sin); 169 sin = mtod(nam, struct sockaddr_in *); 170 bzero((caddr_t)sin, sizeof (*sin)); 171 sin->sin_family = AF_INET; 172 sin->sin_port = inp->inp_lport; 173 sin->sin_addr = inp->inp_laddr; 174 } 175 176 /* 177 * Pass an error to all internet connections 178 * associated with address sin. Call the 179 * protocol specific routine to clean up the 180 * mess afterwards. 181 */ 182 in_pcbnotify(head, dst, errno, abort) 183 struct inpcb *head; 184 register struct in_addr *dst; 185 int errno, (*abort)(); 186 { 187 register struct inpcb *inp, *oinp; 188 int s = splimp(); 189 190 for (inp = head->inp_next; inp != head;) { 191 if (inp->inp_faddr.s_addr != dst->s_addr) { 192 next: 193 inp = inp->inp_next; 194 continue; 195 } 196 if (inp->inp_socket == 0) 197 goto next; 198 inp->inp_socket->so_error = errno; 199 oinp = inp; 200 inp = inp->inp_next; 201 (*abort)(oinp); 202 } 203 splx(s); 204 } 205 206 struct inpcb * 207 in_pcblookup(head, faddr, fport, laddr, lport, flags) 208 struct inpcb *head; 209 struct in_addr faddr, laddr; 210 u_short fport, lport; 211 int flags; 212 { 213 register struct inpcb *inp, *match = 0; 214 int matchwild = 3, wildcard; 215 216 for (inp = head->inp_next; inp != head; inp = inp->inp_next) { 217 if (inp->inp_lport != lport) 218 continue; 219 wildcard = 0; 220 if (inp->inp_laddr.s_addr != 0) { 221 if (laddr.s_addr == 0) 222 wildcard++; 223 else if (inp->inp_laddr.s_addr != laddr.s_addr) 224 continue; 225 } else { 226 if (laddr.s_addr != 0) 227 wildcard++; 228 } 229 if (inp->inp_faddr.s_addr != 0) { 230 if (faddr.s_addr == 0) 231 wildcard++; 232 else if (inp->inp_faddr.s_addr != faddr.s_addr || 233 inp->inp_fport != fport) 234 continue; 235 } else { 236 if (faddr.s_addr != 0) 237 wildcard++; 238 } 239 if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0) 240 continue; 241 if (wildcard < matchwild) { 242 match = inp; 243 matchwild = wildcard; 244 if (matchwild == 0) 245 break; 246 } 247 } 248 return (match); 249 } 250