1 /* socket.c 4.43 82/07/21 */ 2 3 #include "../h/param.h" 4 #include "../h/systm.h" 5 #include "../h/dir.h" 6 #include "../h/user.h" 7 #include "../h/proc.h" 8 #include "../h/file.h" 9 #include "../h/inode.h" 10 #include "../h/buf.h" 11 #include "../h/mbuf.h" 12 #include "../h/protosw.h" 13 #include "../h/socket.h" 14 #include "../h/socketvar.h" 15 #include "../h/stat.h" 16 #include "../h/ioctl.h" 17 #include "../net/in.h" 18 #include "../net/in_systm.h" 19 #include "../net/route.h" 20 21 /* 22 * Socket support routines. 23 * 24 * DEAL WITH INTERRUPT NOTIFICATION. 25 */ 26 27 /* 28 * Create a socket. 29 */ 30 socreate(aso, type, asp, asa, options) 31 struct socket **aso; 32 int type; 33 struct sockproto *asp; 34 struct sockaddr *asa; 35 int options; 36 { 37 register struct protosw *prp; 38 register struct socket *so; 39 struct mbuf *m; 40 int pf, proto, error; 41 42 /* 43 * Use process standard protocol/protocol family if none 44 * specified by address argument. 45 */ 46 if (asp == 0) { 47 pf = PF_INET; /* should be u.u_protof */ 48 proto = 0; 49 } else { 50 pf = asp->sp_family; 51 proto = asp->sp_protocol; 52 } 53 54 /* 55 * If protocol specified, look for it, otherwise 56 * for a protocol of the correct type in the right family. 57 */ 58 if (proto) 59 prp = pffindproto(pf, proto); 60 else 61 prp = pffindtype(pf, type); 62 if (prp == 0) 63 return (EPROTONOSUPPORT); 64 65 /* 66 * Get a socket structure. 67 */ 68 m = m_getclr(M_WAIT); 69 if (m == 0) 70 return (ENOBUFS); 71 so = mtod(m, struct socket *); 72 so->so_options = options; 73 if (options & SO_ACCEPTCONN) { 74 so->so_q = so; 75 so->so_q0 = so; 76 so->so_qlimit = (so->so_options & SO_NEWFDONCONN) ? 5 : 1; 77 } 78 so->so_state = 0; 79 if (u.u_uid == 0) 80 so->so_state = SS_PRIV; 81 82 /* 83 * Attach protocol to socket, initializing 84 * and reserving resources. 85 */ 86 so->so_proto = prp; 87 error = (*prp->pr_usrreq)(so, PRU_ATTACH, 0, asa); 88 if (error) { 89 so->so_state |= SS_NOFDREF; 90 sofree(so); 91 return (error); 92 } 93 *aso = so; 94 return (0); 95 } 96 97 sofree(so) 98 struct socket *so; 99 { 100 101 if (so->so_head) { 102 if (!soqremque(so, 0) && !soqremque(so, 1)) 103 panic("sofree dq"); 104 so->so_head = 0; 105 } 106 if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0) 107 return; 108 sbrelease(&so->so_snd); 109 sbrelease(&so->so_rcv); 110 (void) m_free(dtom(so)); 111 } 112 113 /* 114 * Close a socket on last file table reference removal. 115 * Initiate disconnect if connected. 116 * Free socket when disconnect complete. 117 */ 118 soclose(so, exiting) 119 register struct socket *so; 120 int exiting; 121 { 122 int s = splnet(); /* conservative */ 123 register struct socket *so2; 124 125 if (so->so_options & SO_ACCEPTCONN) { 126 while (so->so_q0 != so) 127 soclose(so->so_q0, 1); 128 while (so->so_q != so) 129 soclose(so->so_q, 1); 130 } 131 if (so->so_pcb == 0) 132 goto discard; 133 if (exiting) 134 so->so_options |= SO_KEEPALIVE; 135 if (so->so_state & SS_ISCONNECTED) { 136 if ((so->so_state & SS_ISDISCONNECTING) == 0) { 137 u.u_error = sodisconnect(so, (struct sockaddr *)0); 138 if (u.u_error) { 139 if (exiting) 140 goto drop; 141 splx(s); 142 return; 143 } 144 } 145 if ((so->so_options & SO_DONTLINGER) == 0) { 146 if ((so->so_state & SS_ISDISCONNECTING) && 147 (so->so_state & SS_NBIO) && 148 exiting == 0) { 149 u.u_error = EINPROGRESS; 150 splx(s); 151 return; 152 } 153 /* should use tsleep here, for at most linger */ 154 while (so->so_state & SS_ISCONNECTED) 155 sleep((caddr_t)&so->so_timeo, PZERO+1); 156 } 157 } 158 drop: 159 if (so->so_pcb) { 160 u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 0, 0); 161 if (exiting == 0 && u.u_error) { 162 splx(s); 163 return; 164 } 165 } 166 discard: 167 so->so_state |= SS_NOFDREF; 168 sofree(so); 169 splx(s); 170 } 171 172 /*ARGSUSED*/ 173 sostat(so, sb) 174 struct socket *so; 175 struct stat *sb; 176 { 177 178 bzero((caddr_t)sb, sizeof (*sb)); /* XXX */ 179 return (0); /* XXX */ 180 } 181 182 /* 183 * Accept connection on a socket. 184 */ 185 soaccept(so, asa) 186 struct socket *so; 187 struct sockaddr *asa; 188 { 189 int s = splnet(); 190 int error; 191 192 error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 0, (caddr_t)asa); 193 splx(s); 194 return (error); 195 } 196 197 /* 198 * Connect socket to a specified address. 199 * If already connected or connecting, then avoid 200 * the protocol entry, to keep its job simpler. 201 */ 202 soconnect(so, asa) 203 struct socket *so; 204 struct sockaddr *asa; 205 { 206 int s = splnet(); 207 int error; 208 209 if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) { 210 error = EISCONN; 211 goto bad; 212 } 213 error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 0, (caddr_t)asa); 214 bad: 215 splx(s); 216 return (error); 217 } 218 219 /* 220 * Disconnect from a socket. 221 * Address parameter is from system call for later multicast 222 * protocols. Check to make sure that connected and no disconnect 223 * in progress (for protocol's sake), and then invoke protocol. 224 */ 225 sodisconnect(so, asa) 226 struct socket *so; 227 struct sockaddr *asa; 228 { 229 int s = splnet(); 230 int error; 231 232 if ((so->so_state & SS_ISCONNECTED) == 0) { 233 error = ENOTCONN; 234 goto bad; 235 } 236 if (so->so_state & SS_ISDISCONNECTING) { 237 error = EALREADY; 238 goto bad; 239 } 240 error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 0, asa); 241 bad: 242 splx(s); 243 return (error); 244 } 245 246 /* 247 * Send on a socket. 248 * If send must go all at once and message is larger than 249 * send buffering, then hard error. 250 * Lock against other senders. 251 * If must go all at once and not enough room now, then 252 * inform user that this would block and do nothing. 253 */ 254 sosend(so, asa) 255 register struct socket *so; 256 struct sockaddr *asa; 257 { 258 struct mbuf *top = 0; 259 register struct mbuf *m, **mp = ⊤ 260 register u_int len; 261 int error = 0, space, s; 262 263 if (sosendallatonce(so) && u.u_count > so->so_snd.sb_hiwat) 264 return (EMSGSIZE); 265 #ifdef notdef 266 /* NEED TO PREVENT BUSY WAITING IN SELECT FOR WRITING */ 267 if ((so->so_snd.sb_flags & SB_LOCK) && (so->so_state & SS_NBIO)) 268 return (EWOULDBLOCK); 269 #endif 270 restart: 271 sblock(&so->so_snd); 272 #define snderr(errno) { error = errno; splx(s); goto release; } 273 274 again: 275 s = splnet(); 276 if (so->so_state & SS_CANTSENDMORE) { 277 psignal(u.u_procp, SIGPIPE); 278 snderr(EPIPE); 279 } 280 if (so->so_error) { 281 error = so->so_error; 282 so->so_error = 0; /* ??? */ 283 splx(s); 284 goto release; 285 } 286 if ((so->so_state & SS_ISCONNECTED) == 0) { 287 if (so->so_proto->pr_flags & PR_CONNREQUIRED) 288 snderr(ENOTCONN); 289 if (asa == 0) 290 snderr(EDESTADDRREQ); 291 } 292 if (top) { 293 error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, top, asa); 294 top = 0; 295 if (error) { 296 splx(s); 297 goto release; 298 } 299 mp = ⊤ 300 } 301 if (u.u_count == 0) { 302 splx(s); 303 goto release; 304 } 305 space = sbspace(&so->so_snd); 306 if (space <= 0 || sosendallatonce(so) && space < u.u_count) { 307 if (so->so_state & SS_NBIO) 308 snderr(EWOULDBLOCK); 309 sbunlock(&so->so_snd); 310 sbwait(&so->so_snd); 311 splx(s); 312 goto restart; 313 } 314 splx(s); 315 while (u.u_count && space > 0) { 316 MGET(m, 1); 317 if (m == NULL) { 318 error = ENOBUFS; /* SIGPIPE? */ 319 goto release; 320 } 321 if (u.u_count >= CLBYTES && space >= CLBYTES) { 322 register struct mbuf *p; 323 MCLGET(p, 1); 324 if (p == 0) 325 goto nopages; 326 m->m_off = (int)p - (int)m; 327 len = CLBYTES; 328 } else { 329 nopages: 330 m->m_off = MMINOFF; 331 len = MIN(MLEN, u.u_count); 332 } 333 iomove(mtod(m, caddr_t), len, B_WRITE); 334 m->m_len = len; 335 *mp = m; 336 mp = &m->m_next; 337 space = sbspace(&so->so_snd); 338 } 339 goto again; 340 341 release: 342 sbunlock(&so->so_snd); 343 if (top) 344 m_freem(top); 345 return (error); 346 } 347 348 soreceive(so, asa) 349 register struct socket *so; 350 struct sockaddr *asa; 351 { 352 register struct mbuf *m, *n; 353 u_int len; 354 int eor, s, error = 0, cnt = u.u_count; 355 caddr_t base = u.u_base; 356 357 restart: 358 sblock(&so->so_rcv); 359 s = splnet(); 360 361 #define rcverr(errno) { error = errno; splx(s); goto release; } 362 if (so->so_rcv.sb_cc == 0) { 363 if (so->so_error) { 364 error = so->so_error; 365 so->so_error = 0; 366 splx(s); 367 goto release; 368 } 369 if (so->so_state & SS_CANTRCVMORE) { 370 splx(s); 371 goto release; 372 } 373 if ((so->so_state & SS_ISCONNECTED) == 0 && 374 (so->so_proto->pr_flags & PR_CONNREQUIRED)) 375 rcverr(ENOTCONN); 376 if (so->so_state & SS_NBIO) 377 rcverr(EWOULDBLOCK); 378 sbunlock(&so->so_rcv); 379 sbwait(&so->so_rcv); 380 splx(s); 381 goto restart; 382 } 383 m = so->so_rcv.sb_mb; 384 if (m == 0) 385 panic("receive"); 386 if (so->so_proto->pr_flags & PR_ADDR) { 387 if (m->m_len != sizeof (struct sockaddr)) 388 panic("soreceive addr"); 389 if (asa) 390 bcopy(mtod(m, caddr_t), (caddr_t)asa, sizeof (*asa)); 391 so->so_rcv.sb_cc -= m->m_len; 392 so->so_rcv.sb_mbcnt -= MSIZE; 393 m = m_free(m); 394 if (m == 0) 395 panic("receive 2"); 396 so->so_rcv.sb_mb = m; 397 } 398 so->so_state &= ~SS_RCVATMARK; 399 if (so->so_oobmark && cnt > so->so_oobmark) 400 cnt = so->so_oobmark; 401 eor = 0; 402 do { 403 len = MIN(m->m_len, cnt); 404 splx(s); 405 iomove(mtod(m, caddr_t), len, B_READ); 406 cnt -= len; 407 s = splnet(); 408 if (len == m->m_len) { 409 eor = (int)m->m_act; 410 sbfree(&so->so_rcv, m); 411 so->so_rcv.sb_mb = m->m_next; 412 MFREE(m, n); 413 } else { 414 m->m_off += len; 415 m->m_len -= len; 416 so->so_rcv.sb_cc -= len; 417 } 418 } while ((m = so->so_rcv.sb_mb) && cnt && !eor); 419 if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0) 420 do { 421 if (m == 0) 422 panic("receive 3"); 423 sbfree(&so->so_rcv, m); 424 eor = (int)m->m_act; 425 so->so_rcv.sb_mb = m->m_next; 426 MFREE(m, n); 427 m = n; 428 } while (eor == 0); 429 if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb) 430 (*so->so_proto->pr_usrreq)(so, PRU_RCVD, 0, 0); 431 if (so->so_oobmark) { 432 so->so_oobmark -= u.u_base - base; 433 if (so->so_oobmark == 0) 434 so->so_state |= SS_RCVATMARK; 435 } 436 release: 437 sbunlock(&so->so_rcv); 438 splx(s); 439 return (error); 440 } 441 442 sohasoutofband(so) 443 struct socket *so; 444 { 445 446 if (so->so_pgrp == 0) 447 return; 448 if (so->so_pgrp > 0) 449 gsignal(so->so_pgrp, SIGURG); 450 else { 451 struct proc *p = pfind(-so->so_pgrp); 452 453 if (p) 454 psignal(p, SIGURG); 455 } 456 } 457 458 /*ARGSUSED*/ 459 soioctl(so, cmd, data) 460 register struct socket *so; 461 int cmd; 462 register char *data; 463 { 464 465 switch (cmd) { 466 467 case FIONBIO: 468 if (*(int *)data) 469 so->so_state |= SS_NBIO; 470 else 471 so->so_state &= ~SS_NBIO; 472 return; 473 474 case FIOASYNC: 475 if (*(int *)data) 476 so->so_state |= SS_ASYNC; 477 else 478 so->so_state &= ~SS_ASYNC; 479 return; 480 481 case SIOCSKEEP: 482 if (*(int *)data) 483 so->so_options &= ~SO_KEEPALIVE; 484 else 485 so->so_options |= SO_KEEPALIVE; 486 return; 487 488 case SIOCGKEEP: 489 *(int *)data = (so->so_options & SO_KEEPALIVE) != 0; 490 return; 491 492 case SIOCSLINGER: 493 so->so_linger = *(int *)data; 494 if (so->so_linger) 495 so->so_options &= ~SO_DONTLINGER; 496 else 497 so->so_options |= SO_DONTLINGER; 498 return; 499 500 case SIOCGLINGER: 501 *(int *)data = so->so_linger; 502 return; 503 504 case SIOCSPGRP: 505 so->so_pgrp = *(int *)data; 506 return; 507 508 case SIOCGPGRP: 509 *(int *)data = so->so_pgrp; 510 return; 511 512 case SIOCDONE: { 513 int flags = *(int *)data; 514 515 flags++; 516 if (flags & FREAD) { 517 int s = splimp(); 518 socantrcvmore(so); 519 sbflush(&so->so_rcv); 520 splx(s); 521 } 522 if (flags & FWRITE) 523 u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_SHUTDOWN, (struct mbuf *)0, 0); 524 return; 525 } 526 527 case SIOCSENDOOB: { 528 char oob = *(char *)data; 529 struct mbuf *m; 530 531 m = m_get(M_DONTWAIT); 532 if (m == 0) { 533 u.u_error = ENOBUFS; 534 return; 535 } 536 m->m_off = MMINOFF; 537 m->m_len = sizeof (char); 538 *mtod(m, char *) = oob; 539 (*so->so_proto->pr_usrreq)(so, PRU_SENDOOB, m, 0); 540 return; 541 } 542 543 case SIOCRCVOOB: { 544 struct mbuf *m = m_get(M_DONTWAIT); 545 546 if (m == 0) { 547 u.u_error = ENOBUFS; 548 return; 549 } 550 m->m_off = MMINOFF; *mtod(m, caddr_t) = 0; 551 (*so->so_proto->pr_usrreq)(so, PRU_RCVOOB, m, 0); 552 *(char *)data = *mtod(m, char *); 553 (void) m_free(m); 554 return; 555 } 556 557 case SIOCATMARK: 558 *(int *)data = (so->so_state&SS_RCVATMARK) != 0; 559 return; 560 561 /* routing table update calls */ 562 case SIOCADDRT: 563 case SIOCDELRT: 564 if (!suser()) 565 return; 566 u.u_error = rtrequest(cmd, (struct rtentry *)data); 567 return; 568 569 /* type/protocol specific ioctls */ 570 } 571 u.u_error = EOPNOTSUPP; 572 } 573