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