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