1 /* uipc_socket.c 4.8 81/11/20 */ 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 (*prp->pr_usrreq)(so, PRU_ATTACH, 0, asa); 79 if (so->so_error) { 80 error = so->so_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_state & SS_ISDISCONNECTING) && 122 (so->so_options & SO_NBIO)) { 123 u.u_error = EINPROGRESS; 124 splx(s); 125 return; 126 } 127 while (so->so_state & SS_ISCONNECTED) 128 sleep((caddr_t)&so->so_timeo, PZERO+1); 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_LOCAL) { 143 struct socket *tso; 144 tso = pso; pso = so; so = tso; 145 } 146 if (pso->so_proto->pr_family != PF_LOCAL) 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_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 if (error) { 279 splx(s); 280 goto release; 281 } 282 top = 0; 283 mp = ⊤ 284 } 285 if (sosendallatonce(so) && sbspace(&so->so_snd) < u.u_count) { 286 if (so->so_options & SO_NBIO) 287 snderr(EWOULDBLOCK); 288 sbunlock(&so->so_snd); 289 sbwait(&so->so_snd); 290 splx(s); 291 goto again; 292 } 293 splx(s); 294 while (u.u_count && (space = sbspace(&so->so_snd)) > 0) { 295 MGET(m, 1); 296 if (m == NULL) { 297 error = ENOBUFS; 298 m_freem(top); 299 goto release; 300 } 301 if (u.u_count >= PGSIZE && space >= NMBPG) { 302 register struct mbuf *p; 303 MPGET(p, 1); 304 if (p == 0) 305 goto nopages; 306 m->m_off = (int)p - (int)m; 307 len = PGSIZE; 308 } else { 309 nopages: 310 m->m_off = MMINOFF; 311 len = MIN(MLEN, u.u_count); 312 } 313 iomove(mtod(m, caddr_t), len, B_WRITE); 314 m->m_len = len; 315 *mp = m; 316 mp = &m->m_next; 317 } 318 s = splnet(); 319 goto again; 320 321 release: 322 sbunlock(&so->so_snd); 323 return (error); 324 } 325 326 soreceive(so, asa) 327 register struct socket *so; 328 struct sockaddr *asa; 329 { 330 register struct mbuf *m, *n; 331 u_int len; 332 int eor, s, error = 0; 333 334 COUNT(SORECEIVE); 335 restart: 336 sblock(&so->so_rcv); 337 s = splnet(); 338 339 #define rcverr(errno) { error = errno; splx(s); goto release; } 340 if (so->so_rcv.sb_cc == 0) { 341 if ((so->so_state & SS_ISCONNECTED) == 0 && 342 (so->so_proto->pr_flags & PR_CONNREQUIRED)) 343 rcverr(ENOTCONN); 344 if (so->so_state & SS_CANTRCVMORE) { 345 splx(s); 346 goto release; 347 } 348 if (so->so_options & SO_NBIO) 349 rcverr (EWOULDBLOCK); 350 sbunlock(&so->so_rcv); 351 sbwait(&so->so_rcv); 352 goto restart; 353 } 354 m = so->so_rcv.sb_mb; 355 if (m == 0) 356 panic("receive"); 357 if ((so->so_proto->pr_flags & PR_ADDR)) { 358 so->so_rcv.sb_mb = m->m_next; 359 if (asa) { 360 so->so_rcv.sb_cc -= m->m_len; 361 len = MIN(m->m_len, sizeof (struct sockaddr)); 362 bcopy(mtod(m, caddr_t), (caddr_t)asa, len); 363 } else 364 bzero((caddr_t)asa, sizeof (*asa)); 365 m = so->so_rcv.sb_mb; 366 if (m == 0) 367 panic("receive 2"); 368 } 369 eor = 0; 370 do { 371 len = MIN(m->m_len, u.u_count); 372 if (len == m->m_len) { 373 eor = (int)m->m_act; 374 sbfree(&so->so_rcv, m); 375 } 376 splx(s); 377 iomove(mtod(m, caddr_t), len, B_READ); 378 s = splnet(); 379 if (len == m->m_len) { 380 MFREE(m, n); 381 } else { 382 m->m_off += len; 383 m->m_len -= len; 384 so->so_rcv.sb_cc -= len; 385 } 386 } while ((m = so->so_rcv.sb_mb) && u.u_count && !eor); 387 if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0) 388 do { 389 if (m == 0) 390 panic("receive 3"); 391 sbfree(&so->so_rcv, m); 392 eor = (int)m->m_act; 393 so->so_rcv.sb_mb = m->m_next; 394 MFREE(m, n); 395 m = n; 396 } while (eor == 0); 397 if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb) 398 (*so->so_proto->pr_usrreq)(so, PRU_RCVD, 0, 0); 399 release: 400 sbunlock(&so->so_rcv); 401 splx(s); 402 return (error); 403 } 404 405 /*ARGSUSED*/ 406 soioctl(so, cmd, cmdp) 407 register struct socket *so; 408 int cmd; 409 register caddr_t cmdp; 410 { 411 412 COUNT(SOIOCTL); 413 switch (cmdp) { 414 415 } 416 switch (so->so_type) { 417 418 case SOCK_STREAM: 419 break; 420 421 case SOCK_DGRAM: 422 break; 423 424 case SOCK_RDM: 425 break; 426 427 case SOCK_RAW: 428 break; 429 430 } 431 } 432