1 /* uipc_socket.c 4.13 81/11/22 */ 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 "../net/inet.h" 17 #include "../net/inet_systm.h" 18 19 /* 20 * Socket support routines. 21 * 22 * DEAL WITH INTERRUPT NOTIFICATION. 23 */ 24 25 /* 26 * Create a socket. 27 */ 28 socreate(aso, type, asp, asa, options) 29 struct socket **aso; 30 int type; 31 struct sockproto *asp; 32 struct sockaddr *asa; 33 int options; 34 { 35 register struct protosw *prp; 36 register struct socket *so; 37 struct mbuf *m; 38 int pf, proto, error; 39 COUNT(SOCREATE); 40 41 /* 42 * Use process standard protocol/protocol family if none 43 * specified by address argument. 44 */ 45 if (asp == 0) { 46 pf = PF_INET; /* should be u.u_protof */ 47 proto = 0; 48 } else { 49 pf = asp->sp_family; 50 proto = asp->sp_protocol; 51 } 52 53 /* 54 * If protocol specified, look for it, otherwise 55 * for a protocol of the correct type in the right family. 56 */ 57 if (proto) 58 prp = pffindproto(pf, proto); 59 else 60 prp = pffindtype(pf, type); 61 if (prp == 0) 62 return (EPROTONOSUPPORT); 63 64 /* 65 * Get a socket structure. 66 */ 67 m = m_getclr(M_WAIT); 68 if (m == 0) 69 return (ENOBUFS); 70 so = mtod(m, struct socket *); 71 so->so_options = options; 72 73 /* 74 * Attach protocol to socket, initializing 75 * and reserving resources. 76 */ 77 so->so_proto = prp; 78 error = (*prp->pr_usrreq)(so, PRU_ATTACH, 0, asa); 79 if (error) { 80 (void) m_free(dtom(so)); 81 return (error); 82 } 83 *aso = so; 84 return (0); 85 } 86 87 sofree(so) 88 struct socket *so; 89 { 90 91 COUNT(SOFREE); 92 if (so->so_pcb || (so->so_state & SS_USERGONE) == 0) 93 return; 94 sbrelease(&so->so_snd); 95 sbrelease(&so->so_rcv); 96 (void) m_free(dtom(so)); 97 } 98 99 /* 100 * Close a socket on last file table reference removal. 101 * Initiate disconnect if connected. 102 * Free socket when disconnect complete. 103 */ 104 soclose(so) 105 register struct socket *so; 106 { 107 int s = splnet(); /* conservative */ 108 109 COUNT(SOCLOSE); 110 if (so->so_pcb == 0) 111 goto discard; 112 if (so->so_state & SS_ISCONNECTED) { 113 if ((so->so_state & SS_ISDISCONNECTING) == 0) { 114 u.u_error = sodisconnect(so, (struct sockaddr *)0); 115 if (u.u_error) { 116 splx(s); 117 return; 118 } 119 } 120 if ((so->so_state & SS_ISDISCONNECTING) && 121 (so->so_options & SO_NBIO)) { 122 u.u_error = EINPROGRESS; 123 splx(s); 124 return; 125 } 126 while (so->so_state & SS_ISCONNECTED) 127 sleep((caddr_t)&so->so_timeo, PZERO+1); 128 } 129 u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 0, 0); 130 discard: 131 so->so_state |= SS_USERGONE; 132 sofree(so); 133 splx(s); 134 } 135 136 sosplice(pso, so) 137 struct socket *pso, *so; 138 { 139 140 COUNT(SOSPLICE); 141 if (pso->so_proto->pr_family != PF_LOCAL) { 142 struct socket *tso; 143 tso = pso; pso = so; so = tso; 144 } 145 if (pso->so_proto->pr_family != PF_LOCAL) 146 return (EOPNOTSUPP); 147 /* check types and buffer space */ 148 /* merge buffers */ 149 return (0); 150 } 151 152 /*ARGSUSED*/ 153 sostat(so, sb) 154 struct socket *so; 155 struct stat *sb; 156 { 157 158 COUNT(SOSTAT); 159 return (EOPNOTSUPP); 160 } 161 162 /* 163 * Accept connection on a socket. 164 */ 165 soaccept(so, asa) 166 struct socket *so; 167 struct sockaddr *asa; 168 { 169 int s = splnet(); 170 int error; 171 172 COUNT(SOACCEPT); 173 if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) { 174 error = EISCONN; 175 goto bad; 176 } 177 if ((so->so_options & SO_ACCEPTCONN) == 0) { 178 error = EINVAL; /* XXX */ 179 goto bad; 180 } 181 error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 0, (caddr_t)asa); 182 bad: 183 splx(s); 184 return (error); 185 } 186 187 /* 188 * Connect socket to a specified address. 189 * If already connected or connecting, then avoid 190 * the protocol entry, to keep its job simpler. 191 */ 192 soconnect(so, asa) 193 struct socket *so; 194 struct sockaddr *asa; 195 { 196 int s = splnet(); 197 int error; 198 199 COUNT(SOCONNECT); 200 if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) { 201 error = EISCONN; 202 goto bad; 203 } 204 error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 0, (caddr_t)asa); 205 bad: 206 splx(s); 207 return (error); 208 } 209 210 /* 211 * Disconnect from a socket. 212 * Address parameter is from system call for later multicast 213 * protocols. Check to make sure that connected and no disconnect 214 * in progress (for protocol's sake), and then invoke protocol. 215 */ 216 sodisconnect(so, asa) 217 struct socket *so; 218 struct sockaddr *asa; 219 { 220 int s = splnet(); 221 int error; 222 223 COUNT(SODISCONNECT); 224 if ((so->so_state & SS_ISCONNECTED) == 0) { 225 error = ENOTCONN; 226 goto bad; 227 } 228 if (so->so_state & SS_ISDISCONNECTING) { 229 error = EALREADY; 230 goto bad; 231 } 232 error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 0, asa); 233 bad: 234 splx(s); 235 return (error); 236 } 237 238 /* 239 * Send on a socket. 240 * If send must go all at once and message is larger than 241 * send buffering, then hard error. 242 * Lock against other senders. 243 * If must go all at once and not enough room now, then 244 * inform user that this would block and do nothing. 245 */ 246 sosend(so, asa) 247 register struct socket *so; 248 struct sockaddr *asa; 249 { 250 struct mbuf *top = 0; 251 register struct mbuf *m, **mp = ⊤ 252 register u_int len; 253 int error = 0, space, s; 254 255 COUNT(SOSEND); 256 if (so->so_state & SS_CANTSENDMORE) 257 return (EPIPE); 258 if (sosendallatonce(so) && u.u_count > so->so_snd.sb_hiwat) 259 return (EMSGSIZE); 260 if ((so->so_snd.sb_flags & SB_LOCK) && (so->so_options & SO_NBIO)) 261 return (EWOULDBLOCK); 262 sblock(&so->so_snd); 263 #define snderr(errno) { error = errno; splx(s); goto release; } 264 265 s = splnet(); 266 nullchk("sosend in", so->so_snd.sb_mb); 267 again: 268 if ((so->so_state & SS_ISCONNECTED) == 0) { 269 if (so->so_proto->pr_flags & PR_CONNREQUIRED) 270 snderr(ENOTCONN); 271 if (asa == 0) 272 snderr(EDESTADDRREQ); 273 } 274 if (so->so_error) 275 snderr(so->so_error); 276 if (top) { 277 error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, top, asa); 278 nullchk("sosend after PRU_SEND", so->so_snd.sb_mb); 279 if (error) { 280 splx(s); 281 goto release; 282 } 283 top = 0; 284 mp = ⊤ 285 } 286 if (u.u_count == 0) { 287 splx(s); 288 goto release; 289 } 290 space = sbspace(&so->so_snd); 291 if (space == 0 || sosendallatonce(so) && space < u.u_count) { 292 if (so->so_options & SO_NBIO) 293 snderr(EWOULDBLOCK); 294 sbunlock(&so->so_snd); 295 sbwait(&so->so_snd); 296 splx(s); 297 goto again; 298 } 299 splx(s); 300 while (u.u_count && space > 0) { 301 MGET(m, 1); 302 if (m == NULL) { 303 error = ENOBUFS; 304 m_freem(top); 305 goto release; 306 } 307 if (u.u_count >= PGSIZE && space >= NMBPG) { 308 register struct mbuf *p; 309 MPGET(p, 1); 310 if (p == 0) 311 goto nopages; 312 m->m_off = (int)p - (int)m; 313 len = PGSIZE; 314 } else { 315 nopages: 316 m->m_off = MMINOFF; 317 len = MIN(MLEN, u.u_count); 318 } 319 iomove(mtod(m, caddr_t), len, B_WRITE); 320 nullblk("sosend", m, len); 321 m->m_len = len; 322 *mp = m; 323 mp = &m->m_next; 324 space = sbspace(&so->so_snd); 325 } 326 nullchk("sosend top", top); 327 s = splnet(); 328 goto again; 329 330 release: 331 sbunlock(&so->so_snd); 332 return (error); 333 } 334 335 soreceive(so, asa) 336 register struct socket *so; 337 struct sockaddr *asa; 338 { 339 register struct mbuf *m, *n; 340 u_int len; 341 int eor, s, error = 0; 342 343 COUNT(SORECEIVE); 344 restart: 345 nullchk("soreceive restart", so->so_rcv.sb_mb); 346 for (m = so->so_rcv.sb_mb; m; m = m->m_next) 347 printf("%d ", m->m_len); 348 printf("\n"); 349 sblock(&so->so_rcv); 350 s = splnet(); 351 352 #define rcverr(errno) { error = errno; splx(s); goto release; } 353 if (so->so_rcv.sb_cc == 0) { 354 if (so->so_state & SS_CANTRCVMORE) { 355 splx(s); 356 goto release; 357 } 358 if ((so->so_state & SS_ISCONNECTED) == 0 && 359 (so->so_proto->pr_flags & PR_CONNREQUIRED)) 360 rcverr(ENOTCONN); 361 if (so->so_options & SO_NBIO) 362 rcverr (EWOULDBLOCK); 363 sbunlock(&so->so_rcv); 364 sbwait(&so->so_rcv); 365 splx(s); 366 goto restart; 367 } 368 printf("soreceive about to\n"); 369 psndrcv(&so->so_snd, &so->so_rcv); 370 m = so->so_rcv.sb_mb; 371 if (m == 0) 372 panic("receive"); 373 if (so->so_proto->pr_flags & PR_ADDR) { 374 printf("m_len %d\n", m->m_len); 375 if (m->m_len != sizeof (struct sockaddr)) 376 panic("soreceive addr"); 377 if (asa) 378 bcopy(mtod(m, caddr_t), (caddr_t)asa, sizeof (*asa)); 379 else 380 bzero((caddr_t)asa, sizeof (*asa)); 381 so->so_rcv.sb_cc -= m->m_len; 382 so->so_rcv.sb_mbcnt -= MSIZE; 383 m = m_free(m); 384 if (m == 0) 385 panic("receive 2"); 386 so->so_rcv.sb_mb = m; 387 } 388 eor = 0; 389 printf("soreceive before receive loop\n"); 390 psndrcv(&so->so_snd, &so->so_rcv); 391 do { 392 len = MIN(m->m_len, u.u_count); 393 if (len == m->m_len) { 394 eor = (int)m->m_act; 395 sbfree(&so->so_rcv, m); 396 } 397 splx(s); 398 nullblk("soreceive", m, len); 399 if (len) 400 printf("%o\n", *mtod(m, caddr_t)); 401 iomove(mtod(m, caddr_t), len, B_READ); 402 s = splnet(); 403 if (len == m->m_len) { 404 MFREE(m, n); 405 so->so_rcv.sb_mb = n; 406 } else { 407 m->m_off += len; 408 m->m_len -= len; 409 so->so_rcv.sb_cc -= len; 410 } 411 } while ((m = so->so_rcv.sb_mb) && u.u_count && !eor); 412 printf("after receive loop\n"); 413 psndrcv(&so->so_snd, &so->so_rcv); 414 if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0) 415 do { 416 if (m == 0) 417 panic("receive 3"); 418 sbfree(&so->so_rcv, m); 419 eor = (int)m->m_act; 420 so->so_rcv.sb_mb = m->m_next; 421 MFREE(m, n); 422 m = n; 423 } while (eor == 0); 424 printf("soreceive after drop remnants\n"); 425 psndrcv(&so->so_snd, &so->so_rcv); 426 if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb) 427 (*so->so_proto->pr_usrreq)(so, PRU_RCVD, 0, 0); 428 nullchk("receive after PRU_RCVD", so->so_rcv.sb_mb); 429 release: 430 sbunlock(&so->so_rcv); 431 splx(s); 432 return (error); 433 } 434 435 /*ARGSUSED*/ 436 soioctl(so, cmd, cmdp) 437 register struct socket *so; 438 int cmd; 439 register caddr_t cmdp; 440 { 441 442 COUNT(SOIOCTL); 443 switch (cmdp) { 444 445 } 446 switch (so->so_type) { 447 448 case SOCK_STREAM: 449 break; 450 451 case SOCK_DGRAM: 452 break; 453 454 case SOCK_RDM: 455 break; 456 457 case SOCK_RAW: 458 break; 459 460 } 461 } 462 463 nullchk(where, m0) 464 char *where; 465 struct mbuf *m0; 466 { 467 register struct mbuf *m; 468 469 for (m = m0; m; m = m->m_next) 470 if (nullany(mtod(m, caddr_t), m->m_len)) 471 goto bad; 472 return; 473 bad: 474 printf("nullchk: %s\n", where); 475 for (m = m0; m; m = m->m_next) 476 printf("\t%x len %d: %s\n", m, m->m_len, 477 nullany(mtod(m, caddr_t), m->m_len) ? "BAD" : "OK"); 478 } 479 480 nullblk(where, m, len) 481 char *where; 482 struct mbuf *m; 483 int len; 484 { 485 486 if (nullany(mtod(m, caddr_t), len)) 487 printf("nullblk: %s m=%x len=%d\n", where, m, len); 488 } 489 490 nullany(cp, len) 491 char *cp; 492 int len; 493 { 494 for (; len > 0; len--) 495 if (*cp++ == 0) 496 return (0); /* XXX */ 497 return (0); 498 } 499