1 #ifdef RCSIDENT 2 static char rcsident[] = "$Header: in_pcb.c,v 1.12 84/11/29 17:02:13 walsh Exp $"; 3 #endif RCSIDENT 4 5 #include "../h/param.h" 6 #include "../h/systm.h" 7 #include "../h/dir.h" 8 #include "../h/user.h" 9 #include "../h/mbuf.h" 10 #include "../h/socket.h" 11 #include "../h/socketvar.h" 12 #include "../h/protosw.h" 13 #include "../h/domain.h" 14 15 #include "../net/if.h" 16 #include "../net/route.h" 17 18 #include "../bbnnet/in.h" 19 #include "../bbnnet/net.h" 20 #include "../bbnnet/in_pcb.h" 21 #include "../bbnnet/in_var.h" 22 23 extern struct rtentry *ip_route(); 24 extern struct domain inetdomain; 25 26 in_pcballoc(so, head) 27 struct socket *so; 28 struct inpcb *head; 29 { 30 register struct mbuf *m; 31 register struct inpcb *inp; 32 33 m = m_getclr(M_DONTWAIT, MT_PCB); 34 if (m == NULL) 35 return (ENOBUFS); 36 37 inp = mtod(m, struct inpcb *); 38 inp->inp_socket = so; 39 40 insque(inp,head); 41 42 so->so_pcb = (caddr_t)inp; 43 44 return (0); 45 } 46 47 /* 48 * changed from 4.2 to accept a structure which has protocol 49 * specific data like how to break down port allocation. 50 */ 51 52 in_pcbbind(inp, nam, advice) 53 register struct inpcb *inp; 54 struct mbuf *nam; 55 struct pr_advice *advice; 56 { 57 register struct socket *so = inp->inp_socket; 58 register struct sockaddr_in *sin; 59 register u_short lport = 0; 60 61 if (in_ifaddr == NULL) 62 return (EADDRNOTAVAIL); 63 /* 64 * socket must not already be bound 65 */ 66 67 if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY) 68 return (EINVAL); 69 70 if (nam == 0) 71 goto noname; 72 sin = mtod(nam, struct sockaddr_in *); 73 if (nam->m_len != sizeof (*sin)) 74 return (EINVAL); 75 /* 76 * Since Berkeley left this out, some of their programs (ftpd) 77 * aren't ready for it 78 * 79 if (sin->sin_family != AF_INET) 80 return (EAFNOSUPPORT); 81 */ 82 83 if (sin->sin_addr.s_addr != INADDR_ANY) 84 { 85 /* some code says ..withnet() */ 86 if (in_iawithaddr(sin->sin_addr, FALSE) == NULL) 87 return (EADDRNOTAVAIL); 88 89 } 90 91 /* user gives port to us in net order */ 92 if (lport = sin->sin_port) 93 { 94 u_short aport; 95 96 /* if portsize > 2 a major rewrite needed to 97 * accomodate longs..... 98 */ 99 100 if (advice->portsize > 1) 101 aport = ntohs(lport); 102 else 103 aport = lport; /* a char is a char */ 104 105 /* 106 * really only a worry for byte size ports 107 */ 108 109 if (aport > advice->maxport) 110 return(EADDRNOTAVAIL); 111 112 if (aport <= advice->rootport && u.u_uid != 0) 113 return (EACCES); 114 115 /* 116 * Check to see if the local address/port is in use. 117 * but, process may use this pair to communicate with 118 * several destinations (each with its own tcp) if he 119 * sets SO_REUSEADDR 120 */ 121 if (advice->bind_used && 122 (*(advice->bind_used))(inp, /* current binding */ 123 lport, /* desired port */ 124 sin->sin_addr.s_addr, /* desired address */ 125 so->so_options & SO_REUSEADDR)) 126 { 127 return (EADDRINUSE); 128 } 129 } 130 inp->inp_laddr = sin->sin_addr; 131 132 noname : 133 /* any ports for random allocation by non-root users? */ 134 if ((advice->maxport <= advice->resvport) && (u.u_uid)) 135 return(EADDRNOTAVAIL); 136 137 if (lport == 0) 138 { 139 /* 140 * Allow for reserved ports for non-super users 141 * so that don't interfere with some project's software. 142 */ 143 u_short possible = advice->nowport; 144 145 do 146 { 147 if (advice->portsize > 1) 148 lport = htons(possible); 149 else 150 lport = possible; 151 152 /* 153 * catch roll over..... 154 */ 155 156 if (possible >= advice->maxport) 157 possible = advice->resvport + 1; 158 else 159 possible++; 160 161 /* 162 * no free ports??? RDP/HMP problem 163 */ 164 165 if (possible == advice->nowport) 166 return(EADDRNOTAVAIL); 167 168 } 169 while (advice->bind_used && 170 (*(advice->bind_used))(inp, lport, inp->inp_laddr.s_addr, 0)); 171 172 advice->nowport = possible; 173 } 174 inp->inp_lport = lport; 175 return (0); 176 } 177 178 /* 179 * Connect from a socket to a specified address. 180 * Both address and port must be specified in argument sin. 181 * If don't have a local address for this socket yet, 182 * then pick one. 183 */ 184 in_pcbconnect(inp, nam, conn_used) 185 struct inpcb *inp; 186 struct mbuf *nam; 187 char *(*conn_used)(); 188 { 189 register struct ifnet *ifp = NULL; 190 register struct in_ifaddr *ia = NULL; 191 register struct sockaddr_in *ifaddr; 192 register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); 193 register struct rtentry *rt; 194 struct sockaddr_in *inpsin; 195 196 if (nam->m_len != sizeof (*sin)) 197 return (EINVAL); 198 if (sin->sin_family != AF_INET) 199 return (EAFNOSUPPORT); 200 if (sin->sin_addr.s_addr == INADDR_ANY || sin->sin_port == 0) 201 return (EADDRNOTAVAIL); 202 203 /* 204 * Find route for connection. For a tcp connecting to a server, 205 * this route will be used for the duration of the connection 206 * (unless redirected...). For a UDP doing a connect, this route 207 * will also be used for the duration. For a UDP unconnected send, 208 * this route will be used for the current packet. 209 * 210 * rtalloc cannot handle routing with both sides already bound 211 */ 212 rt = (struct rtentry *) NULL; 213 214 /* 215 * NOTE: programmers often forget to zero sin_zero[0-1]. 216 * rtalloc does not want to know the port number for routes to hosts. 217 */ 218 inpsin = (struct sockaddr_in *) &inp->inp_route.ro_dst; 219 bcopy((caddr_t)sin, (caddr_t)inpsin, sizeof (*sin)); 220 inpsin->sin_port = 0; 221 222 if (inp->inp_laddr.s_addr == INADDR_ANY) 223 { 224 rtalloc(&inp->inp_route); 225 if (rt = inp->inp_route.ro_rt) 226 ifp = rt->rt_ifp; 227 } 228 else 229 { 230 if (rt = ip_route(&inp->inp_laddr, &sin->sin_addr)) 231 { 232 inp->inp_route.ro_rt = rt; 233 ifp = rt->rt_ifp; 234 } 235 } 236 237 if (ifp == NULL) 238 return (ENETUNREACH); 239 240 /* 241 * find Internet address structure for this interface. 242 */ 243 ia = in_iafromif(ifp); 244 245 if (ia == NULL) 246 /* ??? */ 247 return (ENETUNREACH); 248 249 ifaddr = (struct sockaddr_in *) &ia->ia_addr; 250 251 #ifdef bsd42 252 /* 253 * 8.7.0.2 (on IMP net) can send to 128.11.0.0 (on Ethernet), but 254 * not to 8.0.0.0 255 */ 256 if (in_broadcast(sin->sin_addr) && 257 iptonet(sin->sin_addr) == iptonet(ifaddr->sin_addr) && 258 !(ifp->if_flags & IFF_BROADCAST) ) 259 { 260 if (rt) 261 { 262 rtfree(rt); 263 inp->inp_route.ro_rt = NULL; 264 } 265 return (EADDRNOTAVAIL); 266 } 267 #endif 268 269 if ((*conn_used)(inp, 270 inp->inp_lport, 271 (inp->inp_laddr.s_addr ? inp->inp_laddr.s_addr : ifaddr->sin_addr.s_addr), 272 sin->sin_port, 273 sin->sin_addr.s_addr) != (char *)NULL) 274 { 275 276 if (rt) 277 { 278 rtfree(rt); 279 inp->inp_route.ro_rt = NULL; 280 } 281 return (EADDRINUSE); 282 } 283 284 if (inp->inp_laddr.s_addr == INADDR_ANY) 285 inp->inp_laddr = ifaddr->sin_addr; 286 inp->inp_faddr = sin->sin_addr; 287 inp->inp_fport = sin->sin_port; 288 return (0); 289 } 290 291 in_pcbdisconnect(inp, pcb_free_func) 292 struct inpcb *inp; 293 int (*pcb_free_func)(); 294 { 295 inp->inp_faddr.s_addr = INADDR_ANY; 296 inp->inp_fport = 0; 297 /* 298 * may attach a route to an inpcb several times. For example, 299 * when UDP does unconnected, but bound, sends. 300 */ 301 if (inp->inp_route.ro_rt) 302 { 303 rtfree(inp->inp_route.ro_rt); 304 inp->inp_route.ro_rt = NULL; 305 } 306 307 if (inp->inp_socket->so_state & SS_NOFDREF) 308 in_pcbdetach(inp, pcb_free_func); 309 } 310 311 /* 312 * Don't need to splnet while altering lists, since called from places 313 * where that has already been done. 314 */ 315 in_pcbdetach(inp, pcb_free_func) 316 register struct inpcb *inp; 317 int (*pcb_free_func)(); 318 { 319 register struct socket *so; 320 321 if (so = inp->inp_socket) 322 { 323 so->so_pcb = (caddr_t) NULL; 324 /* inp->inp_socket = (struct socket *) NULL; */ 325 soisdisconnected(so); 326 sofree(so); 327 } 328 else 329 panic("in_pcbdetach"); 330 331 if (inp->inp_route.ro_rt) 332 rtfree(inp->inp_route.ro_rt); 333 334 if (inp->inp_ppcb) 335 (*pcb_free_func)(inp); /* free per-protocol block */ 336 337 remque(inp); 338 339 (void) m_free(dtom(inp)); 340 } 341 342 in_setsockaddr(inp, nam) 343 register struct inpcb *inp; 344 struct mbuf *nam; 345 { 346 register struct sockaddr_in *sin; 347 348 nam->m_len = sizeof (*sin); 349 sin = mtod(nam, struct sockaddr_in *); 350 bzero((caddr_t)sin, sizeof (*sin)); 351 sin->sin_family = AF_INET; 352 sin->sin_port = inp->inp_lport; 353 sin->sin_addr = inp->inp_laddr; 354 } 355 356 in_setpeeraddr(inp, nam) 357 register struct inpcb *inp; 358 struct mbuf *nam; 359 { 360 register struct sockaddr_in *sin; 361 362 nam->m_len = sizeof (*sin); 363 sin = mtod(nam, struct sockaddr_in *); 364 bzero((caddr_t)sin, sizeof (*sin)); 365 sin->sin_family = AF_INET; 366 sin->sin_port = inp->inp_fport; 367 sin->sin_addr = inp->inp_faddr; 368 } 369 370 /* 371 * somewhat different from the one in 4.2 and (I think) substantially 372 * easier to read, though a bit slower. 373 * 374 * fport == 0 if don't want/need match on remote port # (HMP and UDP) 375 */ 376 struct inpcb * 377 in_pcblookup(head,faddr,fport,laddr,lport,wild) 378 struct inpcb *head; 379 u_long faddr, laddr; 380 u_short fport, lport; 381 int wild; 382 { 383 register struct inpcb *inp; 384 385 /* try exact match */ 386 for(inp = head->inp_next; inp != head; inp = inp->inp_next) 387 { 388 /* ports check */ 389 if (inp->inp_lport != lport) 390 continue; 391 392 if (fport && (inp->inp_fport != fport)) 393 continue; 394 395 if ((inp->inp_faddr.s_addr != faddr) || (inp->inp_laddr.s_addr != laddr)) 396 continue; 397 398 /* keep it! */ 399 return(inp); 400 } 401 402 /* try wildcard ? */ 403 if (wild) 404 { 405 for(inp = head->inp_next; inp != head; inp = inp->inp_next) 406 { 407 /* ports again */ 408 if (inp->inp_lport != lport) 409 continue; 410 411 if (fport && (inp->inp_fport != fport) && inp->inp_fport) 412 continue; 413 414 if ((inp->inp_faddr.s_addr) && (inp->inp_faddr.s_addr != faddr)) 415 continue; 416 417 if ((inp->inp_laddr.s_addr) && (inp->inp_laddr.s_addr != laddr)) 418 continue; 419 420 return(inp); 421 } 422 } 423 424 return((struct inpcb *) NULL); 425 } 426 427 428 /* 429 * This only advises process and does not internally close socket, 430 * not so much because the user can do much but close when he gets a 431 * HOSTDEAD/HOSTUNREACH indication, but because it is possible that 432 * the destination host has saved connection state information. (His IMP 433 * interface went down for PM, but the machine stayed up...) 434 * 435 * Also, this makes addition of new protocols easy, since we don't need to 436 * know the name and calling sequence of their close/abort routine. 437 * 438 * We do not close child sockets of listen(2)ers for connection oriented 439 * protocols. We let the protocol do that by timing out connection 440 * establishment. 441 */ 442 inpcb_notify(head, laddr, faddr, error) 443 register struct inpcb *head; 444 register u_long laddr; 445 register u_long faddr; 446 { 447 register struct inpcb *inp; 448 449 for(inp = head->inp_next; inp != head; inp = inp->inp_next) 450 if (((inp->inp_faddr.s_addr == faddr) || (faddr == 0)) && 451 ((inp->inp_laddr.s_addr == laddr) || (laddr == 0))) 452 advise_user(inp->inp_socket, error); 453 } 454 455 advise_user(so, error) 456 struct socket *so; 457 int error; 458 { 459 if (so == 0) 460 return; 461 462 so->so_error = error; 463 464 wakeup((caddr_t) &so->so_timeo); /* in connect(2) */ 465 sowwakeup(so); 466 sorwakeup(so); 467 } 468