1 /*
2  * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
3  *
4  * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
5  */
6 
7 #include <stddef.h>
8 #include <sys/syscall.h>
9 #include <sys/socket.h>
10 #include <cancel.h>
11 #include <bits/kernel-features.h>
12 
13 #if defined(__UCLIBC_USE_TIME64__)
14 #include "internal/time64_helpers.h"
15 #endif
16 
17 #ifdef __NR_socketcall
18 /* Various socketcall numbers */
19 #define SYS_SOCKET      1
20 #define SYS_BIND        2
21 #define SYS_CONNECT     3
22 #define SYS_LISTEN      4
23 #define SYS_ACCEPT      5
24 #define SYS_GETSOCKNAME 6
25 #define SYS_GETPEERNAME 7
26 #define SYS_SOCKETPAIR  8
27 #define SYS_SEND        9
28 #define SYS_RECV        10
29 #define SYS_SENDTO      11
30 #define SYS_RECVFROM    12
31 #define SYS_SHUTDOWN    13
32 #define SYS_SETSOCKOPT  14
33 #define SYS_GETSOCKOPT  15
34 #define SYS_SENDMSG     16
35 #define SYS_RECVMSG     17
36 #define SYS_ACCEPT4     18
37 #define SYS_RECVMMSG    19
38 #define SYS_SENDMMSG    20
39 #endif
40 
41 /* exposed on x86 since Linux commit 9dea5dc921b5f4045a18c63eb92e84dc274d17eb */
42 #if defined(__sparc__) || defined(__i386__)
43 #undef __NR_accept
44 #undef __NR_accept4
45 #undef __NR_bind
46 #undef __NR_connect
47 #undef __NR_getpeername
48 #undef __NR_getsockname
49 #undef __NR_getsockopt
50 #undef __NR_listen
51 #undef __NR_recv
52 #undef __NR_recvfrom
53 #undef __NR_recvmsg
54 #undef __NR_send
55 #undef __NR_sendmsg
56 #undef __NR_sendto
57 #undef __NR_setsockopt
58 #undef __NR_shutdown
59 #undef __NR_socket
60 #undef __NR_socketpair
61 #endif
62 
63 #ifdef L_accept
__NC(accept)64 static int __NC(accept)(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
65 {
66 # ifdef __NR_accept
67 	return INLINE_SYSCALL(accept, 3, sockfd, addr, addrlen);
68 # elif defined(__NR_socketcall)
69 	unsigned long args[3];
70 
71 	args[0] = sockfd;
72 	args[1] = (unsigned long) addr;
73 	args[2] = (unsigned long) addrlen;
74 
75 	return __socketcall(SYS_ACCEPT, args);
76 # endif
77 }
78 CANCELLABLE_SYSCALL(int, accept, (int sockfd, struct sockaddr *addr, socklen_t *addrlen),
79 		    (sockfd, addr, addrlen))
lt_libc_hidden(accept)80 lt_libc_hidden(accept)
81 #endif
82 
83 #ifdef L_accept4
84 static int __NC(accept4)(int fd, struct sockaddr *addr, socklen_t *addrlen, int flags)
85 {
86 # ifdef __NR_accept4
87 	return INLINE_SYSCALL(accept4, 4, fd, addr, addrlen, flags);
88 # elif defined(__NR_socketcall)
89 	unsigned long args[4];
90 
91 	args[0] = fd;
92 	args[1] = (unsigned long) addr;
93 	args[2] = (unsigned long) addrlen;
94 	args[3] = flags;
95 
96 	return __socketcall(SYS_ACCEPT4, args);
97 #endif
98 }
99 CANCELLABLE_SYSCALL(int, accept4, (int fd, struct sockaddr *addr, socklen_t *addrlen, int flags),
100 		    (fd, addr, addrlen, flags))
lt_libc_hidden(accept4)101 lt_libc_hidden(accept4)
102 #endif
103 
104 #ifdef L_bind
105 int bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen)
106 {
107 # ifdef __NR_bind
108 	return INLINE_SYSCALL(bind, 3, sockfd, myaddr, addrlen);
109 # elif defined(__NR_socketcall)
110 	unsigned long args[3];
111 
112 	args[0] = sockfd;
113 	args[1] = (unsigned long) myaddr;
114 	args[2] = addrlen;
115 	return __socketcall(SYS_BIND, args);
116 # endif
117 }
libc_hidden_def(bind)118 libc_hidden_def(bind)
119 #endif
120 
121 #ifdef L_connect
122 static int __NC(connect)(int sockfd, const struct sockaddr *saddr, socklen_t addrlen)
123 {
124 # ifdef __NR_connect
125 	return INLINE_SYSCALL(connect, 3, sockfd, saddr, addrlen);
126 # elif defined(__NR_socketcall)
127 	unsigned long args[3];
128 
129 	args[0] = sockfd;
130 	args[1] = (unsigned long) saddr;
131 	args[2] = addrlen;
132 	return __socketcall(SYS_CONNECT, args);
133 # endif
134 }
135 CANCELLABLE_SYSCALL(int, connect, (int sockfd, const struct sockaddr *saddr, socklen_t addrlen),
136 		    (sockfd, saddr, addrlen))
lt_libc_hidden(connect)137 lt_libc_hidden(connect)
138 #endif
139 
140 #ifdef L_getpeername
141 int getpeername(int sockfd, struct sockaddr *addr, socklen_t *paddrlen)
142 {
143 # ifdef __NR_getpeername
144 	return INLINE_SYSCALL(getpeername, 3, sockfd, addr, paddrlen);
145 # elif defined(__NR_socketcall)
146 	unsigned long args[3];
147 
148 	args[0] = sockfd;
149 	args[1] = (unsigned long) addr;
150 	args[2] = (unsigned long) paddrlen;
151 	return __socketcall(SYS_GETPEERNAME, args);
152 # endif
153 }
154 #endif
155 
156 #ifdef L_getsockname
getsockname(int sockfd,struct sockaddr * addr,socklen_t * paddrlen)157 int getsockname(int sockfd, struct sockaddr *addr, socklen_t * paddrlen)
158 {
159 # ifdef __NR_getsockname
160 	return INLINE_SYSCALL(getsockname, 3, sockfd, addr, paddrlen);
161 # elif defined(__NR_socketcall)
162 	unsigned long args[3];
163 
164 	args[0] = sockfd;
165 	args[1] = (unsigned long) addr;
166 	args[2] = (unsigned long) paddrlen;
167 	return __socketcall(SYS_GETSOCKNAME, args);
168 # endif
169 }
libc_hidden_def(getsockname)170 libc_hidden_def(getsockname)
171 #endif
172 
173 #ifdef L_getsockopt
174 int getsockopt(int fd, int level, int optname, void *optval,
175 	       socklen_t *optlen)
176 {
177 # ifdef __NR_getsockopt
178 	return INLINE_SYSCALL(getsockopt, 5, fd, level, optname, optval, optlen);
179 # elif defined(__NR_socketcall)
180 	unsigned long args[5];
181 
182 	args[0] = fd;
183 	args[1] = level;
184 	args[2] = optname;
185 	args[3] = (unsigned long) optval;
186 	args[4] = (unsigned long) optlen;
187 	return (__socketcall(SYS_GETSOCKOPT, args));
188 # endif
189 }
190 #endif
191 
192 #ifdef L_listen
listen(int sockfd,int backlog)193 int listen(int sockfd, int backlog)
194 {
195 # ifdef __NR_listen
196 	return INLINE_SYSCALL(listen, 2, sockfd, backlog);
197 # elif defined(__NR_socketcall)
198 	unsigned long args[2];
199 
200 	args[0] = sockfd;
201 	args[1] = backlog;
202 	return __socketcall(SYS_LISTEN, args);
203 # endif
204 }
libc_hidden_def(listen)205 libc_hidden_def(listen)
206 #endif
207 
208 #ifdef L_recv
209 static ssize_t __NC(recv)(int sockfd, void *buffer, size_t len, int flags)
210 {
211 # ifdef __NR_recv
212 	return (ssize_t)INLINE_SYSCALL(recv, 4, sockfd, buffer, len, flags);
213 # elif defined __NR_recvfrom && defined _syscall6
214 	return __NC(recvfrom)(sockfd, buffer, len, flags, NULL, NULL);
215 # elif defined(__NR_socketcall)
216 	unsigned long args[4];
217 
218 	args[0] = sockfd;
219 	args[1] = (unsigned long) buffer;
220 	args[2] = len;
221 	args[3] = flags;
222 	return (ssize_t)__socketcall(SYS_RECV, args);
223 # endif
224 }
225 CANCELLABLE_SYSCALL(ssize_t, recv, (int sockfd, void *buffer, size_t len, int flags),
226 		    (sockfd, buffer, len, flags))
lt_libc_hidden(recv)227 lt_libc_hidden(recv)
228 #endif
229 
230 #ifdef L_recvfrom
231 ssize_t __NC(recvfrom)(int sockfd, void *buffer, size_t len, int flags,
232 		       struct sockaddr *to, socklen_t *tolen)
233 {
234 # if defined __NR_recvfrom && defined _syscall6
235 	return (ssize_t)INLINE_SYSCALL(recvfrom, 6, sockfd, buffer, len,
236 				       flags, to, tolen);
237 # elif defined(__NR_socketcall)
238 	unsigned long args[6];
239 
240 	args[0] = sockfd;
241 	args[1] = (unsigned long) buffer;
242 	args[2] = len;
243 	args[3] = flags;
244 	args[4] = (unsigned long) to;
245 	args[5] = (unsigned long) tolen;
246 	return (ssize_t)__socketcall(SYS_RECVFROM, args);
247 # endif
248 }
249 CANCELLABLE_SYSCALL(ssize_t, recvfrom, (int sockfd, void *buffer, size_t len,
250 					int flags, struct sockaddr *to, socklen_t *tolen),
251 		    (sockfd, buffer, len, flags, to, tolen))
lt_libc_hidden(recvfrom)252 lt_libc_hidden(recvfrom)
253 #endif
254 
255 #ifdef L_recvmsg
256 static ssize_t __NC(recvmsg)(int sockfd, struct msghdr *msg, int flags)
257 {
258 # ifdef __NR_recvmsg
259 	return (ssize_t)INLINE_SYSCALL(recvmsg, 3, sockfd, msg, flags);
260 # elif defined(__NR_socketcall)
261 	unsigned long args[3];
262 
263 	args[0] = sockfd;
264 	args[1] = (unsigned long) msg;
265 	args[2] = flags;
266 	return (ssize_t)__socketcall(SYS_RECVMSG, args);
267 # endif
268 }
269 CANCELLABLE_SYSCALL(ssize_t, recvmsg, (int sockfd, struct msghdr *msg, int flags),
270 		    (sockfd, msg, flags))
lt_libc_hidden(recvmsg)271 lt_libc_hidden(recvmsg)
272 #endif
273 
274 #ifdef L_recvmmsg
275 #ifdef __ASSUME_RECVMMSG_SYSCALL
276 static ssize_t __NC(recvmmsg)(int sockfd, struct mmsghdr *msg, size_t vlen,
277 			      int flags, struct timespec *tmo)
278 {
279 # if defined(__UCLIBC_USE_TIME64__) && defined(__NR_recvmmsg_time64)
280 	return (ssize_t)INLINE_SYSCALL(recvmmsg_time64, 5, sockfd, msg, vlen, flags, TO_TS64_P(tmo));
281 # elif defined(__NR_recvmmsg)
282 	return (ssize_t)INLINE_SYSCALL(recvmmsg, 5, sockfd, msg, vlen, flags, tmo);
283 # elif __NR_socketcall
284 	unsigned long args[5];
285 
286 	args[0] = sockfd;
287 	args[1] = (unsigned long) msg;
288 	args[2] = vlen;
289 	args[3] = flags;
290 	args[4] = (unsigned long) tmo;
291 	return (ssize_t)__socketcall(SYS_RECVMMSG, args);
292 # endif
293 }
294 CANCELLABLE_SYSCALL(ssize_t, recvmmsg,
295 		    (int sockfd, struct mmsghdr *msg, size_t vlen, int flags,
296 		     struct timespec *tmo),
297 		    (sockfd, msg, vlen, flags, tmo))
lt_libc_hidden(recvmmsg)298 lt_libc_hidden(recvmmsg)
299 #endif
300 #endif
301 
302 #ifdef L_send
303 static ssize_t __NC(send)(int sockfd, const void *buffer, size_t len, int flags)
304 {
305 # ifdef __NR_send
306 	return (ssize_t)INLINE_SYSCALL(send, 4, sockfd, buffer, len, flags);
307 # elif defined __NR_sendto && defined _syscall6
308 	return __NC(sendto)(sockfd, buffer, len, flags, NULL, 0);
309 # elif defined(__NR_socketcall)
310 	unsigned long args[4];
311 
312 	args[0] = sockfd;
313 	args[1] = (unsigned long) buffer;
314 	args[2] = len;
315 	args[3] = flags;
316 	return (ssize_t)__socketcall(SYS_SEND, args);
317 # endif
318 }
319 CANCELLABLE_SYSCALL(ssize_t, send, (int sockfd, const void *buffer, size_t len, int flags),
320 		    (sockfd, buffer, len, flags))
lt_libc_hidden(send)321 lt_libc_hidden(send)
322 #endif
323 
324 #ifdef L_sendmsg
325 static ssize_t __NC(sendmsg)(int sockfd, const struct msghdr *msg, int flags)
326 {
327 # ifdef __NR_sendmsg
328 	return (ssize_t)INLINE_SYSCALL(sendmsg, 3, sockfd, msg, flags);
329 # elif defined(__NR_socketcall)
330 	unsigned long args[3];
331 
332 	args[0] = sockfd;
333 	args[1] = (unsigned long) msg;
334 	args[2] = flags;
335 	return (ssize_t)__socketcall(SYS_SENDMSG, args);
336 # endif
337 }
338 CANCELLABLE_SYSCALL(ssize_t, sendmsg, (int sockfd, const struct msghdr *msg, int flags),
339 		    (sockfd, msg, flags))
lt_libc_hidden(sendmsg)340 lt_libc_hidden(sendmsg)
341 #endif
342 
343 #ifdef L_sendmmsg
344 #ifdef __ASSUME_SENDMMSG_SYSCALL
345 static ssize_t __NC(sendmmsg)(int sockfd, struct mmsghdr *msg, size_t vlen,
346 			      int flags)
347 {
348 # ifdef __NR_sendmmsg
349 	return (ssize_t)INLINE_SYSCALL(sendmmsg, 4, sockfd, msg, vlen, flags);
350 # elif __NR_socketcall
351 	unsigned long args[4];
352 
353 	args[0] = sockfd;
354 	args[1] = (unsigned long) msg;
355 	args[2] = vlen;
356 	args[3] = flags;
357 	return (ssize_t)__socketcall(SYS_SENDMMSG, args);
358 # endif
359 }
360 CANCELLABLE_SYSCALL(ssize_t, sendmmsg,
361 		    (int sockfd, struct mmsghdr *msg, size_t vlen, int flags),
362 		    (sockfd, msg, vlen, flags))
lt_libc_hidden(sendmmsg)363 lt_libc_hidden(sendmmsg)
364 #endif
365 #endif
366 
367 #ifdef L_sendto
368 ssize_t __NC(sendto)(int sockfd, const void *buffer, size_t len, int flags,
369 		     const struct sockaddr *to, socklen_t tolen)
370 {
371 # if defined __NR_sendto && defined _syscall6
372 	return (ssize_t)INLINE_SYSCALL(sendto, 6, sockfd, buffer, len, flags, to, tolen);
373 # elif defined(__NR_socketcall)
374 	unsigned long args[6];
375 
376 	args[0] = sockfd;
377 	args[1] = (unsigned long) buffer;
378 	args[2] = len;
379 	args[3] = flags;
380 	args[4] = (unsigned long) to;
381 	args[5] = tolen;
382 	return (ssize_t)__socketcall(SYS_SENDTO, args);
383 # endif
384 }
385 CANCELLABLE_SYSCALL(ssize_t, sendto, (int sockfd, const void *buffer, size_t len,
386 				      int flags, const struct sockaddr *to, socklen_t tolen),
387 		    (sockfd, buffer, len, flags, to, tolen))
lt_libc_hidden(sendto)388 lt_libc_hidden(sendto)
389 #endif
390 
391 #ifdef L_setsockopt
392 int setsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen)
393 {
394 # ifdef __NR_setsockopt
395 	return INLINE_SYSCALL(setsockopt, 5, fd, level, optname, optval, optlen);
396 # elif defined(__NR_socketcall)
397 	unsigned long args[5];
398 
399 	args[0] = fd;
400 	args[1] = level;
401 	args[2] = optname;
402 	args[3] = (unsigned long) optval;
403 	args[4] = optlen;
404 	return __socketcall(SYS_SETSOCKOPT, args);
405 # endif
406 }
libc_hidden_def(setsockopt)407 libc_hidden_def(setsockopt)
408 #endif
409 
410 #ifdef L_shutdown
411 int shutdown(int sockfd, int how)
412 {
413 # ifdef __NR_shutdown
414 	return INLINE_SYSCALL(shutdown, 2, sockfd, how);
415 # elif defined(__NR_socketcall)
416 	unsigned long args[2];
417 
418 	args[0] = sockfd;
419 	args[1] = how;
420 	return __socketcall(SYS_SHUTDOWN, args);
421 # endif
422 }
423 #endif
424 
425 #ifdef L_socket
socket(int family,int type,int protocol)426 int socket(int family, int type, int protocol)
427 {
428 # ifdef __NR_socket
429 	return INLINE_SYSCALL(socket, 3, family, type, protocol);
430 # elif defined(__NR_socketcall)
431 	unsigned long args[3];
432 
433 	args[0] = family;
434 	args[1] = type;
435 	args[2] = (unsigned long) protocol;
436 	return __socketcall(SYS_SOCKET, args);
437 # endif
438 }
libc_hidden_def(socket)439 libc_hidden_def(socket)
440 #endif
441 
442 #ifdef L_socketpair
443 int socketpair(int family, int type, int protocol, int sockvec[2])
444 {
445 # ifdef __NR_socketpair
446 	return INLINE_SYSCALL(socketpair, 4, family, type, protocol, sockvec);
447 # elif defined(__NR_socketcall)
448 	unsigned long args[4];
449 
450 	args[0] = family;
451 	args[1] = type;
452 	args[2] = protocol;
453 	args[3] = (unsigned long) sockvec;
454 	return __socketcall(SYS_SOCKETPAIR, args);
455 # endif
456 }
457 #endif
458