1 /* uipc_socket.c 4.19 81/12/19 */ 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/in.h" 17 #include "../net/in_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 } 130 u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 0, 0); 131 discard: 132 so->so_state |= SS_USERGONE; 133 sofree(so); 134 splx(s); 135 } 136 137 sosplice(pso, so) 138 struct socket *pso, *so; 139 { 140 141 COUNT(SOSPLICE); 142 if (pso->so_proto->pr_family != PF_UNIX) { 143 struct socket *tso; 144 tso = pso; pso = so; so = tso; 145 } 146 if (pso->so_proto->pr_family != PF_UNIX) 147 return (EOPNOTSUPP); 148 /* check types and buffer space */ 149 /* merge buffers */ 150 return (0); 151 } 152 153 /*ARGSUSED*/ 154 sostat(so, sb) 155 struct socket *so; 156 struct stat *sb; 157 { 158 159 COUNT(SOSTAT); 160 return (EOPNOTSUPP); 161 } 162 163 /* 164 * Accept connection on a socket. 165 */ 166 soaccept(so, asa) 167 struct socket *so; 168 struct sockaddr *asa; 169 { 170 int s = splnet(); 171 int error; 172 173 COUNT(SOACCEPT); 174 if ((so->so_options & SO_ACCEPTCONN) == 0) { 175 error = EINVAL; /* XXX */ 176 goto bad; 177 } 178 if ((so->so_state & SS_CONNAWAITING) == 0) { 179 error = ENOTCONN; 180 goto bad; 181 } 182 so->so_state &= ~SS_CONNAWAITING; 183 error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 0, (caddr_t)asa); 184 bad: 185 splx(s); 186 return (error); 187 } 188 189 /* 190 * Connect socket to a specified address. 191 * If already connected or connecting, then avoid 192 * the protocol entry, to keep its job simpler. 193 */ 194 soconnect(so, asa) 195 struct socket *so; 196 struct sockaddr *asa; 197 { 198 int s = splnet(); 199 int error; 200 201 COUNT(SOCONNECT); 202 if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) { 203 error = EISCONN; 204 goto bad; 205 } 206 error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 0, (caddr_t)asa); 207 bad: 208 splx(s); 209 return (error); 210 } 211 212 /* 213 * Disconnect from a socket. 214 * Address parameter is from system call for later multicast 215 * protocols. Check to make sure that connected and no disconnect 216 * in progress (for protocol's sake), and then invoke protocol. 217 */ 218 sodisconnect(so, asa) 219 struct socket *so; 220 struct sockaddr *asa; 221 { 222 int s = splnet(); 223 int error; 224 225 COUNT(SODISCONNECT); 226 if ((so->so_state & SS_ISCONNECTED) == 0) { 227 error = ENOTCONN; 228 goto bad; 229 } 230 if (so->so_state & SS_ISDISCONNECTING) { 231 error = EALREADY; 232 goto bad; 233 } 234 error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 0, asa); 235 bad: 236 splx(s); 237 return (error); 238 } 239 240 /* 241 * Send on a socket. 242 * If send must go all at once and message is larger than 243 * send buffering, then hard error. 244 * Lock against other senders. 245 * If must go all at once and not enough room now, then 246 * inform user that this would block and do nothing. 247 */ 248 sosend(so, asa) 249 register struct socket *so; 250 struct sockaddr *asa; 251 { 252 struct mbuf *top = 0; 253 register struct mbuf *m, **mp = ⊤ 254 register u_int len; 255 int error = 0, space, s; 256 257 COUNT(SOSEND); 258 if (so->so_state & SS_CANTSENDMORE) 259 return (EPIPE); 260 if (sosendallatonce(so) && u.u_count > so->so_snd.sb_hiwat) 261 return (EMSGSIZE); 262 if ((so->so_snd.sb_flags & SB_LOCK) && (so->so_options & SO_NBIO)) 263 return (EWOULDBLOCK); 264 sblock(&so->so_snd); 265 #define snderr(errno) { error = errno; splx(s); goto release; } 266 267 s = splnet(); 268 again: 269 if (so->so_error) { 270 error = so->so_error; 271 so->so_error = 0; 272 splx(s); 273 goto release; 274 } 275 if ((so->so_state & SS_ISCONNECTED) == 0) { 276 if (so->so_proto->pr_flags & PR_CONNREQUIRED) 277 snderr(ENOTCONN); 278 if (asa == 0) 279 snderr(EDESTADDRREQ); 280 } 281 if (top) { 282 error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, top, asa); 283 if (error) { 284 splx(s); 285 goto release; 286 } 287 top = 0; 288 mp = ⊤ 289 } 290 if (u.u_count == 0) { 291 splx(s); 292 goto release; 293 } 294 space = sbspace(&so->so_snd); 295 if (space == 0 || sosendallatonce(so) && space < u.u_count) { 296 if (so->so_options & SO_NBIO) 297 snderr(EWOULDBLOCK); 298 sbunlock(&so->so_snd); 299 sbwait(&so->so_snd); 300 splx(s); 301 goto again; 302 } 303 splx(s); 304 while (u.u_count && space > 0) { 305 MGET(m, 1); 306 if (m == NULL) { 307 error = ENOBUFS; 308 m_freem(top); 309 goto release; 310 } 311 if (u.u_count >= CLBYTES && space >= CLBYTES) { 312 register struct mbuf *p; 313 MCLGET(p, 1); 314 if (p == 0) 315 goto nopages; 316 m->m_off = (int)p - (int)m; 317 len = CLBYTES; 318 } else { 319 nopages: 320 m->m_off = MMINOFF; 321 len = MIN(MLEN, u.u_count); 322 } 323 iomove(mtod(m, caddr_t), len, B_WRITE); 324 m->m_len = len; 325 *mp = m; 326 mp = &m->m_next; 327 space = sbspace(&so->so_snd); 328 } 329 s = splnet(); 330 goto again; 331 332 release: 333 sbunlock(&so->so_snd); 334 return (error); 335 } 336 337 soreceive(so, asa) 338 register struct socket *so; 339 struct sockaddr *asa; 340 { 341 register struct mbuf *m, *n; 342 u_int len; 343 int eor, s, error = 0; 344 345 COUNT(SORECEIVE); 346 restart: 347 sblock(&so->so_rcv); 348 s = splnet(); 349 350 #define rcverr(errno) { error = errno; splx(s); goto release; } 351 if (so->so_rcv.sb_cc == 0) { 352 if (so->so_error) { 353 error = so->so_error; 354 so->so_error = 0; 355 splx(s); 356 goto release; 357 } 358 if (so->so_state & SS_CANTRCVMORE) { 359 splx(s); 360 goto release; 361 } 362 if ((so->so_state & SS_ISCONNECTED) == 0 && 363 (so->so_proto->pr_flags & PR_CONNREQUIRED)) 364 rcverr(ENOTCONN); 365 if (so->so_options & SO_NBIO) 366 rcverr(EWOULDBLOCK); 367 sbunlock(&so->so_rcv); 368 sbwait(&so->so_rcv); 369 splx(s); 370 goto restart; 371 } 372 m = so->so_rcv.sb_mb; 373 if (m == 0) 374 panic("receive"); 375 if (so->so_proto->pr_flags & PR_ADDR) { 376 if (m->m_len != sizeof (struct sockaddr)) 377 panic("soreceive addr"); 378 if (asa) 379 bcopy(mtod(m, caddr_t), (caddr_t)asa, sizeof (*asa)); 380 so->so_rcv.sb_cc -= m->m_len; 381 so->so_rcv.sb_mbcnt -= MSIZE; 382 m = m_free(m); 383 if (m == 0) 384 panic("receive 2"); 385 so->so_rcv.sb_mb = m; 386 } 387 eor = 0; 388 do { 389 len = MIN(m->m_len, u.u_count); 390 if (len == m->m_len) { 391 eor = (int)m->m_act; 392 sbfree(&so->so_rcv, m); 393 } 394 splx(s); 395 iomove(mtod(m, caddr_t), len, B_READ); 396 s = splnet(); 397 if (len == m->m_len) { 398 MFREE(m, n); 399 so->so_rcv.sb_mb = n; 400 } else { 401 m->m_off += len; 402 m->m_len -= len; 403 so->so_rcv.sb_cc -= len; 404 } 405 } while ((m = so->so_rcv.sb_mb) && u.u_count && !eor); 406 if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0) 407 do { 408 if (m == 0) 409 panic("receive 3"); 410 sbfree(&so->so_rcv, m); 411 eor = (int)m->m_act; 412 so->so_rcv.sb_mb = m->m_next; 413 MFREE(m, n); 414 m = n; 415 } while (eor == 0); 416 if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb) 417 (*so->so_proto->pr_usrreq)(so, PRU_RCVD, 0, 0); 418 release: 419 sbunlock(&so->so_rcv); 420 splx(s); 421 return (error); 422 } 423 424 /*ARGSUSED*/ 425 soioctl(so, cmd, cmdp) 426 register struct socket *so; 427 int cmd; 428 register caddr_t cmdp; 429 { 430 431 COUNT(SOIOCTL); 432 switch (cmdp) { 433 434 } 435 switch (so->so_type) { 436 437 case SOCK_STREAM: 438 break; 439 440 case SOCK_DGRAM: 441 break; 442 443 case SOCK_RDM: 444 break; 445 446 case SOCK_RAW: 447 break; 448 449 } 450 } 451