Commit | Line | Data |
---|---|---|
225bec1b | 1 | /* uipc_syscalls.c 4.8 81/11/21 */ |
c8c7dd0e BJ |
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" | |
c8c7dd0e BJ |
12 | #include "../h/protosw.h" |
13 | #include "../h/socket.h" | |
14 | #include "../h/socketvar.h" | |
c8c7dd0e BJ |
15 | #include "../net/inet.h" |
16 | #include "../net/inet_systm.h" | |
17 | ||
18 | /* | |
19 | * Socket system call interface. | |
20 | * | |
21 | * These routines interface the socket routines to UNIX, | |
22 | * isolating the system interface from the socket-protocol interface. | |
23 | * | |
cc15ab5d | 24 | * TODO: |
cc15ab5d | 25 | * SO_INTNOTIFY |
c8c7dd0e BJ |
26 | */ |
27 | ||
2b4b57cd | 28 | static struct sockproto localproto = { PF_LOCAL, 0 }; |
c8c7dd0e | 29 | /* |
cc15ab5d | 30 | * Pipe system call interface. |
c8c7dd0e | 31 | */ |
cc15ab5d | 32 | spipe() |
c8c7dd0e | 33 | { |
cc15ab5d BJ |
34 | register struct file *rf, *wf; |
35 | struct socket *rso, *wso; | |
36 | int r; | |
2b4b57cd | 37 | COUNT(SPIPE); |
cc15ab5d | 38 | |
2b4b57cd BJ |
39 | u.u_error = socreate(&rso, SOCK_STREAM, |
40 | &localproto, (struct sockaddr *)0, 0); | |
cc15ab5d | 41 | if (u.u_error) |
c8c7dd0e | 42 | return; |
2b4b57cd BJ |
43 | u.u_error = socreate(&wso, SOCK_STREAM, |
44 | &localproto, (struct sockaddr *)0, 0); | |
c8c7dd0e | 45 | if (u.u_error) |
cc15ab5d BJ |
46 | goto free; |
47 | rf = falloc(); | |
48 | if (rf == NULL) | |
49 | goto free2; | |
50 | r = u.u_r.r_val1; | |
51 | rf->f_flag = FREAD|FSOCKET; | |
52 | rf->f_socket = rso; | |
53 | wf = falloc(); | |
54 | if (wf == NULL) | |
55 | goto free3; | |
56 | wf->f_flag = FWRITE|FSOCKET; | |
57 | wf->f_socket = wso; | |
58 | u.u_r.r_val2 = u.u_r.r_val1; | |
59 | u.u_r.r_val1 = r; | |
225bec1b | 60 | if (piconnect(wso, rso) == 0) |
cc15ab5d | 61 | goto free4; |
c8c7dd0e | 62 | return; |
cc15ab5d BJ |
63 | free4: |
64 | wf->f_count = 0; | |
c8c7dd0e | 65 | u.u_ofile[u.u_r.r_val1] = 0; |
cc15ab5d BJ |
66 | free3: |
67 | rf->f_count = 0; | |
68 | u.u_ofile[r] = 0; | |
69 | free2: | |
4ad99bae | 70 | wso->so_state |= SS_USERGONE; |
cc15ab5d BJ |
71 | sofree(wso); |
72 | free: | |
4ad99bae | 73 | rso->so_state |= SS_USERGONE; |
cc15ab5d | 74 | sofree(rso); |
c8c7dd0e BJ |
75 | } |
76 | ||
c8c7dd0e | 77 | /* |
cc15ab5d | 78 | * Splice system call interface. |
c8c7dd0e | 79 | */ |
cc15ab5d | 80 | ssplice() |
c8c7dd0e | 81 | { |
cc15ab5d BJ |
82 | register struct a { |
83 | int fd1; | |
84 | int fd2; | |
85 | } *ap = (struct a *)u.u_ap; | |
86 | struct file *f1, *f2; | |
2b4b57cd | 87 | COUNT(SSPLICE); |
c8c7dd0e | 88 | |
cc15ab5d BJ |
89 | f1 = getf(ap->fd1); |
90 | if (f1 == NULL) | |
91 | return; | |
92 | f2 = getf(ap->fd2); | |
93 | if (f2 == NULL) | |
94 | return; | |
2b4b57cd BJ |
95 | if (f1 == f2) { |
96 | u.u_error = EINVAL; | |
97 | return; | |
98 | } | |
cc15ab5d BJ |
99 | if ((f1->f_flag & FSOCKET) == 0 || (f2->f_flag & FSOCKET) == 0) { |
100 | u.u_error = ENOTSOCK; | |
101 | return; | |
102 | } | |
103 | if (f1->f_count > 1 || f2->f_count > 1) { | |
104 | u.u_error = ETOOMANYREFS; | |
105 | return; | |
106 | } | |
2b4b57cd | 107 | u.u_error = sosplice(f1->f_socket, f2->f_socket); |
cc15ab5d BJ |
108 | if (u.u_error) |
109 | return; | |
110 | u.u_ofile[ap->fd1] = 0; | |
111 | u.u_ofile[ap->fd2] = 0; | |
112 | f1->f_count = 0; | |
113 | f2->f_count = 0; | |
c8c7dd0e BJ |
114 | } |
115 | ||
116 | /* | |
2b4b57cd | 117 | * Socket system call interface. Copy sa arguments |
cc15ab5d BJ |
118 | * set up file descriptor and call internal socket |
119 | * creation routine. | |
c8c7dd0e | 120 | */ |
cc15ab5d | 121 | ssocket() |
c8c7dd0e | 122 | { |
cc15ab5d BJ |
123 | register struct a { |
124 | int type; | |
2b4b57cd BJ |
125 | struct sockproto *asp; |
126 | struct sockaddr *asa; | |
cc15ab5d BJ |
127 | int options; |
128 | } *uap = (struct a *)u.u_ap; | |
2b4b57cd BJ |
129 | struct sockproto sp; |
130 | struct sockaddr sa; | |
131 | struct socket *so; | |
cc15ab5d | 132 | register struct file *fp; |
2b4b57cd | 133 | COUNT(SSOCKET); |
c8c7dd0e | 134 | |
cc15ab5d BJ |
135 | if ((fp = falloc()) == NULL) |
136 | return; | |
137 | fp->f_flag = FSOCKET|FREAD|FWRITE; | |
2b4b57cd BJ |
138 | if (uap->asp && copyin((caddr_t)uap->asp, (caddr_t)&sp, sizeof (sp)) || |
139 | uap->asa && copyin((caddr_t)uap->asa, (caddr_t)&sa, sizeof (sa))) { | |
cc15ab5d BJ |
140 | u.u_error = EFAULT; |
141 | return; | |
c8c7dd0e | 142 | } |
2b4b57cd BJ |
143 | u.u_error = socreate(&so, uap->type, |
144 | uap->asp ? &sp : 0, uap->asa ? &sa : 0, uap->options); | |
cc15ab5d BJ |
145 | if (u.u_error) |
146 | goto bad; | |
2b4b57cd | 147 | fp->f_socket = so; |
cc15ab5d BJ |
148 | return; |
149 | bad: | |
150 | u.u_ofile[u.u_r.r_val1] = 0; | |
151 | fp->f_count = 0; | |
c8c7dd0e | 152 | } |
ae921915 | 153 | |
2b4b57cd BJ |
154 | /* |
155 | * Accept system call interface. | |
156 | */ | |
ae921915 BJ |
157 | saccept() |
158 | { | |
2b4b57cd BJ |
159 | register struct a { |
160 | int fdes; | |
161 | struct sockaddr *asa; | |
162 | } *uap = (struct a *)u.u_ap; | |
163 | struct sockaddr sa; | |
164 | register struct file *fp; | |
165 | struct socket *so; | |
166 | int s; | |
167 | COUNT(SACCEPT); | |
ae921915 | 168 | |
2b4b57cd BJ |
169 | if (uap->asa && useracc((caddr_t)uap->asa, sizeof (sa), B_WRITE)==0) { |
170 | u.u_error = EFAULT; | |
171 | return; | |
172 | } | |
173 | fp = getf(uap->fdes); | |
174 | if (fp == 0) | |
175 | return; | |
176 | if ((fp->f_flag & FSOCKET) == 0) { | |
177 | u.u_error = ENOTSOCK; | |
178 | return; | |
179 | } | |
180 | s = splnet(); | |
181 | so = fp->f_socket; | |
182 | if ((so->so_options & SO_NBIO) && | |
183 | (so->so_state & SS_CONNAWAITING) == 0) { | |
184 | u.u_error = EWOULDBLOCK; | |
185 | splx(s); | |
186 | return; | |
187 | } | |
188 | u.u_error = soaccept(so, &sa); | |
189 | if (u.u_error) { | |
190 | splx(s); | |
191 | return; | |
192 | } | |
193 | /* deal with new file descriptor case */ | |
194 | /* u.u_r.r_val1 = ... */ | |
195 | splx(s); | |
ae921915 BJ |
196 | } |
197 | ||
c8c7dd0e BJ |
198 | /* |
199 | * Connect socket to foreign peer; system call | |
2b4b57cd | 200 | * interface. Copy sa arguments and call internal routine. |
c8c7dd0e BJ |
201 | */ |
202 | sconnect() | |
203 | { | |
204 | register struct a { | |
2b4b57cd BJ |
205 | int fdes; |
206 | struct sockaddr *a; | |
c8c7dd0e | 207 | } *uap = (struct a *)u.u_ap; |
2b4b57cd | 208 | struct sockaddr sa; |
c8c7dd0e BJ |
209 | register struct file *fp; |
210 | register struct socket *so; | |
211 | int s; | |
2b4b57cd | 212 | COUNT(SCONNECT); |
c8c7dd0e | 213 | |
2b4b57cd | 214 | if (copyin((caddr_t)uap->a, (caddr_t)&sa, sizeof (sa))) { |
c8c7dd0e BJ |
215 | u.u_error = EFAULT; |
216 | return; | |
217 | } | |
218 | fp = getf(uap->fdes); | |
219 | if (fp == 0) | |
220 | return; | |
221 | if ((fp->f_flag & FSOCKET) == 0) { | |
222 | u.u_error = ENOTSOCK; | |
223 | return; | |
224 | } | |
225 | so = fp->f_socket; | |
2b4b57cd | 226 | u.u_error = soconnect(so, &sa); |
c8c7dd0e BJ |
227 | if (u.u_error) |
228 | return; | |
229 | s = splnet(); | |
cc15ab5d BJ |
230 | if ((so->so_options & SO_NBIO) && |
231 | (so->so_state & SS_ISCONNECTING)) { | |
c8c7dd0e | 232 | u.u_error = EINPROGRESS; |
cc15ab5d | 233 | splx(s); |
c8c7dd0e BJ |
234 | return; |
235 | } | |
cc15ab5d | 236 | while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) |
c8c7dd0e BJ |
237 | sleep((caddr_t)&so->so_timeo, PZERO+1); |
238 | u.u_error = so->so_error; | |
cc15ab5d BJ |
239 | so->so_error = 0; |
240 | splx(s); | |
c8c7dd0e BJ |
241 | } |
242 | ||
243 | /* | |
244 | * Disconnect socket from foreign peer; system call | |
2b4b57cd | 245 | * interface. Copy sa arguments and call internal routine. |
c8c7dd0e BJ |
246 | */ |
247 | sdisconnect() | |
248 | { | |
249 | register struct a { | |
250 | int fdes; | |
2b4b57cd | 251 | struct sockaddr *asa; |
c8c7dd0e | 252 | } *uap = (struct a *)u.u_ap; |
2b4b57cd | 253 | struct sockaddr sa; |
c8c7dd0e | 254 | register struct file *fp; |
cc15ab5d | 255 | register struct socket *so; |
c8c7dd0e | 256 | int s; |
2b4b57cd | 257 | COUNT(SDISCONNECT); |
c8c7dd0e | 258 | |
2b4b57cd BJ |
259 | if (uap->asa && |
260 | copyin((caddr_t)uap->asa, (caddr_t)&sa, sizeof (sa))) { | |
c8c7dd0e BJ |
261 | u.u_error = EFAULT; |
262 | return; | |
263 | } | |
264 | fp = getf(uap->fdes); | |
265 | if (fp == 0) | |
266 | return; | |
267 | if ((fp->f_flag & FSOCKET) == 0) { | |
268 | u.u_error = ENOTSOCK; | |
269 | return; | |
270 | } | |
cc15ab5d | 271 | so = fp->f_socket; |
2b4b57cd | 272 | u.u_error = sodisconnect(so, uap->asa ? &sa : 0); |
c8c7dd0e BJ |
273 | if (u.u_error) |
274 | return; | |
275 | s = splnet(); | |
cc15ab5d BJ |
276 | if ((so->so_options&SO_NBIO) && (so->so_state&SS_ISDISCONNECTING)) { |
277 | u.u_error = EINPROGRESS; | |
278 | splx(s); | |
279 | return; | |
280 | } | |
281 | while (so->so_state & SS_ISDISCONNECTING) | |
c8c7dd0e BJ |
282 | sleep((caddr_t)&so->so_timeo, PZERO+1); |
283 | u.u_error = so->so_error; | |
cc15ab5d BJ |
284 | so->so_error = 0; |
285 | splx(s); | |
c8c7dd0e BJ |
286 | } |
287 | ||
288 | /* | |
289 | * Send data on socket. | |
290 | */ | |
291 | ssend() | |
292 | { | |
293 | register struct a { | |
294 | int fdes; | |
2b4b57cd | 295 | struct sockaddr *asa; |
c8c7dd0e | 296 | caddr_t cbuf; |
2b4b57cd | 297 | unsigned count; |
c8c7dd0e BJ |
298 | } *uap = (struct a *)u.u_ap; |
299 | register struct file *fp; | |
2b4b57cd BJ |
300 | struct sockaddr sa; |
301 | COUNT(SSEND); | |
c8c7dd0e BJ |
302 | |
303 | fp = getf(uap->fdes); | |
304 | if (fp == 0) | |
305 | return; | |
306 | if ((fp->f_flag & FSOCKET) == 0) { | |
307 | u.u_error = ENOTSOCK; | |
308 | return; | |
309 | } | |
c8c7dd0e BJ |
310 | u.u_count = uap->count; |
311 | u.u_segflg = 0; | |
cc15ab5d | 312 | if (useracc(uap->cbuf, uap->count, B_READ) == 0 || |
2b4b57cd | 313 | uap->asa && copyin((caddr_t)uap->asa, (caddr_t)&sa, sizeof (sa))) { |
c8c7dd0e BJ |
314 | u.u_error = EFAULT; |
315 | return; | |
316 | } | |
2b4b57cd | 317 | u.u_error = sosend(fp->f_socket, uap->asa ? &sa : 0); |
c8c7dd0e BJ |
318 | } |
319 | ||
cc15ab5d BJ |
320 | /* |
321 | * Receive data on socket. | |
322 | */ | |
323 | sreceive() | |
324 | { | |
325 | register struct a { | |
326 | int fdes; | |
2b4b57cd | 327 | struct sockaddr *asa; |
cc15ab5d | 328 | caddr_t cbuf; |
ae921915 | 329 | u_int count; |
cc15ab5d BJ |
330 | } *uap = (struct a *)u.u_ap; |
331 | register struct file *fp; | |
2b4b57cd BJ |
332 | struct sockaddr sa; |
333 | COUNT(SRECEIVE); | |
cc15ab5d BJ |
334 | |
335 | fp = getf(uap->fdes); | |
336 | if (fp == 0) | |
337 | return; | |
338 | if ((fp->f_flag & FSOCKET) == 0) { | |
339 | u.u_error = ENOTSOCK; | |
340 | return; | |
341 | } | |
cc15ab5d BJ |
342 | u.u_count = uap->count; |
343 | u.u_segflg = 0; | |
344 | if (useracc(uap->cbuf, uap->count, B_WRITE) == 0 || | |
2b4b57cd | 345 | uap->asa && copyin((caddr_t)uap->asa, (caddr_t)&sa, sizeof (sa))) { |
cc15ab5d BJ |
346 | u.u_error = EFAULT; |
347 | return; | |
348 | } | |
2b4b57cd BJ |
349 | u.u_error = soreceive(fp->f_socket, uap->asa ? &sa : 0); |
350 | if (u.u_error) | |
351 | return; | |
352 | if (uap->asa) | |
353 | (void) copyout((caddr_t)&sa, (caddr_t)uap->asa, sizeof (sa)); | |
cc15ab5d | 354 | } |
a3076b07 BJ |
355 | |
356 | /* | |
357 | * Get socket address. | |
358 | */ | |
359 | ssocketaddr() | |
360 | { | |
361 | register struct a { | |
362 | int fdes; | |
363 | struct sockaddr *asa; | |
364 | } *uap = (struct a *)u.u_ap; | |
365 | register struct file *fp; | |
366 | COUNT(SSOCKETADDR); | |
367 | ||
368 | fp = getf(uap->fdes); | |
369 | if (fp == 0) | |
370 | return; | |
371 | if ((fp->f_flag & FSOCKET) == 0) { | |
372 | u.u_error = ENOTSOCK; | |
373 | return; | |
374 | } | |
2752c877 BJ |
375 | if (copyout((caddr_t)&fp->f_socket->so_addr, (caddr_t)uap->asa, |
376 | sizeof (struct sockaddr))) { | |
377 | u.u_error = EFAULT; | |
378 | return; | |
379 | } | |
380 | } |