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