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