Commit | Line | Data |
---|---|---|
2b4b57cd | 1 | /* uipc_syscalls.c 4.4 81/11/18 */ |
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; | |
2b4b57cd | 60 | if (piconnect(rso, wso) == 0) |
cc15ab5d | 61 | goto free4; |
2b4b57cd | 62 | rso->so_isfilerefd = wso->so_isfilerefd = 1; |
c8c7dd0e | 63 | return; |
cc15ab5d BJ |
64 | free4: |
65 | wf->f_count = 0; | |
c8c7dd0e | 66 | u.u_ofile[u.u_r.r_val1] = 0; |
cc15ab5d BJ |
67 | free3: |
68 | rf->f_count = 0; | |
69 | u.u_ofile[r] = 0; | |
70 | free2: | |
71 | sofree(wso); | |
72 | free: | |
73 | sofree(rso); | |
c8c7dd0e BJ |
74 | } |
75 | ||
c8c7dd0e | 76 | /* |
cc15ab5d | 77 | * Splice system call interface. |
c8c7dd0e | 78 | */ |
cc15ab5d | 79 | ssplice() |
c8c7dd0e | 80 | { |
cc15ab5d BJ |
81 | register struct a { |
82 | int fd1; | |
83 | int fd2; | |
84 | } *ap = (struct a *)u.u_ap; | |
85 | struct file *f1, *f2; | |
2b4b57cd | 86 | COUNT(SSPLICE); |
c8c7dd0e | 87 | |
cc15ab5d BJ |
88 | f1 = getf(ap->fd1); |
89 | if (f1 == NULL) | |
90 | return; | |
91 | f2 = getf(ap->fd2); | |
92 | if (f2 == NULL) | |
93 | return; | |
2b4b57cd BJ |
94 | if (f1 == f2) { |
95 | u.u_error = EINVAL; | |
96 | return; | |
97 | } | |
cc15ab5d BJ |
98 | if ((f1->f_flag & FSOCKET) == 0 || (f2->f_flag & FSOCKET) == 0) { |
99 | u.u_error = ENOTSOCK; | |
100 | return; | |
101 | } | |
102 | if (f1->f_count > 1 || f2->f_count > 1) { | |
103 | u.u_error = ETOOMANYREFS; | |
104 | return; | |
105 | } | |
2b4b57cd | 106 | u.u_error = sosplice(f1->f_socket, f2->f_socket); |
cc15ab5d BJ |
107 | if (u.u_error) |
108 | return; | |
109 | u.u_ofile[ap->fd1] = 0; | |
110 | u.u_ofile[ap->fd2] = 0; | |
111 | f1->f_count = 0; | |
112 | f2->f_count = 0; | |
c8c7dd0e BJ |
113 | } |
114 | ||
115 | /* | |
2b4b57cd | 116 | * Socket system call interface. Copy sa arguments |
cc15ab5d BJ |
117 | * set up file descriptor and call internal socket |
118 | * creation routine. | |
c8c7dd0e | 119 | */ |
cc15ab5d | 120 | ssocket() |
c8c7dd0e | 121 | { |
cc15ab5d BJ |
122 | register struct a { |
123 | int type; | |
2b4b57cd BJ |
124 | struct sockproto *asp; |
125 | struct sockaddr *asa; | |
cc15ab5d BJ |
126 | int options; |
127 | } *uap = (struct a *)u.u_ap; | |
2b4b57cd BJ |
128 | struct sockproto sp; |
129 | struct sockaddr sa; | |
130 | struct socket *so; | |
cc15ab5d | 131 | register struct file *fp; |
2b4b57cd | 132 | COUNT(SSOCKET); |
c8c7dd0e | 133 | |
cc15ab5d BJ |
134 | if ((fp = falloc()) == NULL) |
135 | return; | |
136 | fp->f_flag = FSOCKET|FREAD|FWRITE; | |
2b4b57cd BJ |
137 | if (uap->asp && copyin((caddr_t)uap->asp, (caddr_t)&sp, sizeof (sp)) || |
138 | uap->asa && copyin((caddr_t)uap->asa, (caddr_t)&sa, sizeof (sa))) { | |
cc15ab5d BJ |
139 | u.u_error = EFAULT; |
140 | return; | |
c8c7dd0e | 141 | } |
2b4b57cd BJ |
142 | u.u_error = socreate(&so, uap->type, |
143 | uap->asp ? &sp : 0, uap->asa ? &sa : 0, uap->options); | |
cc15ab5d BJ |
144 | if (u.u_error) |
145 | goto bad; | |
2b4b57cd BJ |
146 | fp->f_socket = so; |
147 | so->so_isfilerefd = 1; | |
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 | } |