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