tools/adflib: build only host variant which is used by Sam440 target
[AROS.git] / workbench / network / stacks / AROSTCP / bsdsocket / api / amiga_syscalls.c
blob7c928306c1df8fb335af049eba1d71d58f28d5fa
1 /*
2 * Copyright (C) 1993 AmiTCP/IP Group, <amitcp-group@hut.fi>
3 * Helsinki University of Technology, Finland.
4 * All rights reserved.
5 * Copyright (C) 2005 Neil Cafferkey
6 * Copyright (C) 2005 Pavel Fedin
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
20 * MA 02111-1307, USA.
24 #include <conf.h>
26 #include <sys/param.h>
27 #include <sys/systm.h>
28 #include <sys/malloc.h>
29 #include <sys/mbuf.h>
30 #include <sys/protosw.h>
31 #include <sys/socket.h>
32 #include <sys/socketvar.h>
33 #include <sys/synch.h>
34 #include <sys/errno.h>
36 #include <aros/asmcall.h>
37 #include <aros/libcall.h>
38 #include <exec/types.h>
39 #include <exec/libraries.h>
40 #include <exec/semaphores.h>
42 #include <api/amiga_api.h>
43 #include <api/amiga_libcallentry.h>
44 #include <api/sockargs.h>
46 #include <bsdsocket/socketbasetags.h>
48 #include <kern/uipc_socket_protos.h>
49 #include <kern/uipc_socket2_protos.h>
51 #ifdef DEBUG_SYSCALLS
52 void dump_sockaddr_in (struct sockaddr_in *name, struct SocketBase *libPtr)
54 __log(LOG_DEBUG,"sockaddr_in contents:");
55 __log(LOG_DEBUG,"sin_len: %u", name->sin_len);
56 __log(LOG_DEBUG,"sin_family: %u", name->sin_family);
57 __log(LOG_DEBUG,"sin_port: %u", name->sin_port);
58 __log(LOG_DEBUG,"sin_addr: %s", __Inet_NtoA(name->sin_addr.s_addr, libPtr));
60 #endif
62 LONG __socket(LONG domain, LONG type, LONG protocol, struct SocketBase *libPtr)
64 struct socket *so;
65 LONG fd, error;
67 #if defined(__AROS__)
68 D(bug("[AROSTCP](amiga_syscalls.c) __socket()\n"));
69 #endif
71 CHECK_TASK();
73 if (error = sdFind(libPtr, &fd))
74 goto Return;
76 ObtainSyscallSemaphore(libPtr);
77 error = socreate(domain, &so, type, protocol);
78 ReleaseSyscallSemaphore(libPtr);
80 if (! error) {
82 * Tell the link library about the new fd
84 if (libPtr->fdCallback)
85 error = AROS_UFC2(int, libPtr->fdCallback,
86 AROS_UFCA(int, fd, D0),
87 AROS_UFCA(int, FDCB_ALLOC, D1));
88 if (! error) {
89 so->so_refcnt = 1; /* reference count is pure AmiTCP addition */
90 libPtr->dTable[fd] = so;
91 so->so_pgid = libPtr;
92 FD_SET(fd, (fd_set *)(libPtr->dTable + libPtr->dTableSize));
93 #if defined(__AROS__)
94 D(bug("[AROSTCP](amiga_syscalls.c) __socket: created socket 0x%p fd = %ld libPtr = 0x%p\n", so, fd, libPtr));
95 #endif
96 DEVENTS(__log(LOG_DEBUG,"socket(): created socket 0x%p fd = %ld libPtr = 0x%p", so, fd, libPtr);)
100 Return: API_STD_RETURN(error, fd);
103 AROS_LH3(LONG, socket,
104 AROS_LHA(LONG, domain, D0),
105 AROS_LHA(LONG, type, D1),
106 AROS_LHA(LONG, protocol, D2),
107 struct SocketBase *, libPtr, 5, UL)
109 AROS_LIBFUNC_INIT
111 #if defined(__AROS__)
112 D(bug("[AROSTCP](amiga_syscalls.c) UL_socket(%ld, %ld, %ld)\n", domain, type, protocol));
113 #endif
115 DSYSCALLS(__log(LOG_DEBUG,"socket(%ld, %ld, %ld) called", domain, type, protocol);)
116 return __socket(domain, type, protocol, libPtr);
117 AROS_LIBFUNC_EXIT
121 /*LONG SAVEDS bind(
122 REG(d0, LONG s),
123 REG(a0, caddr_t name),
124 REG(d1, LONG namelen),
125 REG(a6, struct SocketBase *libPtr))*/
126 AROS_LH3(LONG, bind,
127 AROS_LHA(LONG, s, D0),
128 AROS_LHA(caddr_t, name, A0),
129 AROS_LHA(LONG, namelen, D1),
130 struct SocketBase *, libPtr, 6, UL)
132 AROS_LIBFUNC_INIT
133 struct socket *so;
134 struct mbuf *nam;
135 LONG error;
137 #if defined(__AROS__)
138 D(bug("[AROSTCP](amiga_syscalls.c) UL_bind(%ld, sockaddr_in, %ld)\n", s, namelen));
139 #endif
141 CHECK_TASK();
142 DSYSCALLS(__log(LOG_DEBUG,"bind(%ld, sockaddr_in, %ld) called", s, namelen);)
143 DSYSCALLS(dump_sockaddr_in((struct sockaddr_in *)name, libPtr);)
144 ObtainSyscallSemaphore(libPtr);
146 if (error = getSock(libPtr, s, &so))
147 goto Return;
148 if (error = sockArgs(&nam, name, namelen, MT_SONAME))
149 goto Return;
150 error = sobind(so, nam);
151 m_freem(nam);
153 Return:
154 ReleaseSyscallSemaphore(libPtr);
155 API_STD_RETURN(error, 0);
156 AROS_LIBFUNC_EXIT
159 /*LONG SAVEDS listen(
160 REG(d0, LONG s),
161 REG(d1, LONG backlog),
162 REG(a6, struct SocketBase *libPtr))*/
163 AROS_LH2(LONG, listen,
164 AROS_LHA(LONG, s, D0),
165 AROS_LHA(LONG, backlog, D1),
166 struct SocketBase *, libPtr, 7, UL)
168 AROS_LIBFUNC_INIT
169 struct socket *so;
170 LONG error;
172 #if defined(__AROS__)
173 D(bug("[AROSTCP](amiga_syscalls.c) UL_Listen(%ld, %ld)\n", s, backlog));
174 #endif
176 CHECK_TASK();
177 DSYSCALLS(__log("listen(%ld, %ld) called ", s, backlog);)
178 ObtainSyscallSemaphore(libPtr);
180 if (error = getSock(libPtr, s, &so))
181 goto Return;
182 error = solisten(so, backlog);
184 Return:
185 ReleaseSyscallSemaphore(libPtr);
186 API_STD_RETURN(error, 0);
187 AROS_LIBFUNC_EXIT
190 /*LONG SAVEDS accept(
191 REG(d0, LONG s),
192 REG(a0, caddr_t name),
193 REG(a1, ULONG *anamelen),
194 REG(a6, struct SocketBase *libPtr))*/
195 AROS_LH3(LONG, accept,
196 AROS_LHA(LONG, s, D0),
197 AROS_LHA(caddr_t, name, A0),
198 AROS_LHA(socklen_t *, anamelen, A1),
199 struct SocketBase *, libPtr, 8, UL)
201 AROS_LIBFUNC_INIT
202 struct socket *so;
203 struct mbuf *nam;
204 spl_t old_spl;
205 LONG error, fd;
206 D(int i;)
208 #if defined(__AROS__)
209 D(bug("[AROSTCP](amiga_syscalls.c) UL_accept(%ld)\n", s));
210 #endif
212 CHECK_TASK();
213 DSYSCALLS(__log("accept(%ld) called", s);)
214 ObtainSyscallSemaphore(libPtr);
216 if (error = getSock(libPtr, s, &so))
217 goto Return;
219 old_spl = splnet();
220 if ((so->so_options & SO_ACCEPTCONN) == 0) {
221 error = EINVAL;
222 goto Return_spl;
224 if ((so->so_state & SS_NBIO) && so->so_qlen == 0) {
225 error = EWOULDBLOCK;
226 goto Return_spl;
228 while (so->so_qlen == 0 && so->so_error == 0) {
229 if (so->so_state & SS_CANTRCVMORE) {
230 so->so_error = ECONNABORTED;
231 break;
233 if (error = tsleep(libPtr, (caddr_t)&so->so_timeo, netcon, NULL)) {
234 goto Return_spl;
237 if (so->so_error) {
238 error = so->so_error;
239 so->so_error = 0;
240 goto Return_spl;
243 if (error = sdFind(libPtr, &fd)) {
244 goto Return_spl;
248 * Tell the link library about the new fd
250 if (libPtr->fdCallback)
251 if (error = AROS_UFC2(int, libPtr->fdCallback,
252 AROS_UFCA(int, fd, D0),
253 AROS_UFCA(int, FDCB_ALLOC, D1)))
254 goto Return_spl;
257 struct socket *aso = so->so_q;
258 if (soqremque(aso, 1) == 0)
259 panic("accept");
260 so = aso;
263 libPtr->dTable[fd] = so;
264 FD_SET(fd, (fd_set *)(libPtr->dTable + libPtr->dTableSize));
265 so->so_refcnt = 1; /* pure AmiTCP addition */
267 nam = m_get(M_WAIT, MT_SONAME);
268 (void)soaccept(so, nam); /* is this always successful */
269 if (name) {
270 if (*anamelen > nam->m_len)
271 *anamelen = nam->m_len;
272 /* SHOULD COPY OUT A CHAIN HERE */
273 aligned_bcopy(mtod(nam, caddr_t), (caddr_t)name, (u_int)*anamelen);
275 m_freem(nam);
277 Return_spl:
278 splx(old_spl);
280 Return:
281 ReleaseSyscallSemaphore(libPtr);
282 DSYSCALLS(__log(LOG_DEBUG,"accept() executed");)
283 DSYSCALLS(dump_sockaddr_in((struct sockaddr_in *)name, libPtr);)
284 API_STD_RETURN(error, fd);
285 AROS_LIBFUNC_EXIT
288 LONG __connect(LONG s, caddr_t name, LONG namelen, struct SocketBase *libPtr)
290 /*register*/ struct socket *so;
291 struct mbuf *nam;
292 LONG error;
293 spl_t old_spl;
295 #if defined(__AROS__)
296 D(bug("[AROSTCP](amiga_syscalls.c) __connect()\n"));
297 #endif
299 CHECK_TASK();
300 ObtainSyscallSemaphore(libPtr);
302 if (error = getSock(libPtr, s, &so))
303 goto Return;
304 if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) {
305 error = EALREADY;
306 goto Return;
308 if (error = sockArgs(&nam, name, namelen, MT_SONAME))
309 goto Return;
310 error = soconnect(so, nam);
311 if (error)
312 goto bad;
313 if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) {
314 m_freem(nam);
315 error = EINPROGRESS;
316 goto Return;
318 old_spl = splnet();
319 while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0)
320 if (error = tsleep(libPtr,(caddr_t)&so->so_timeo, netcon, NULL))
321 break;
322 if (error == 0) {
323 error = so->so_error;
324 so->so_error = 0;
326 splx(old_spl);
327 bad:
328 so->so_state &= ~SS_ISCONNECTING;
329 m_freem(nam);
330 if (error == ERESTART)
331 error = EINTR;
333 Return:
334 ReleaseSyscallSemaphore(libPtr);
335 API_STD_RETURN(error, 0);
338 AROS_LH3(LONG, connect,
339 AROS_LHA(LONG, s, D0),
340 AROS_LHA(caddr_t, name, A0),
341 AROS_LHA(LONG, namelen, D1),
342 struct SocketBase *, libPtr, 9, UL)
344 AROS_LIBFUNC_INIT
346 #if defined(__AROS__)
347 D(bug("[AROSTCP](amiga_syscalls.c) UL_connect(%ld, sockaddr_in, %ld)\n", s, namelen));
348 #endif
350 DSYSCALLS(__log(LOG_DEBUG, "connect(%ld, sockaddr_in, %ld) called", s, namelen);)
351 DSYSCALLS(dump_sockaddr_in((struct sockaddr_in *) name, libPtr);)
352 return __connect(s, name, namelen, libPtr);
353 AROS_LIBFUNC_EXIT
356 /*LONG SAVEDS shutdown(
357 REG(d0, LONG s),
358 REG(d1, LONG how),
359 REG(a6, struct SocketBase *libPtr))*/
360 AROS_LH2(LONG, shutdown,
361 AROS_LHA(LONG, s, D0),
362 AROS_LHA(LONG, how, D1),
363 struct SocketBase *, libPtr, 14, UL)
365 AROS_LIBFUNC_INIT
366 struct socket *so;
367 LONG error;
369 #if defined(__AROS__)
370 D(bug("[AROSTCP](amiga_syscalls.c) UL_shutdown(%ld, %ld)\n", s, how));
371 #endif
373 CHECK_TASK();
374 DSYSCALLS(__log(LOG_DEBUG,"shutdown(%ld, %ld) called", s, how);)
375 ObtainSyscallSemaphore(libPtr);
377 if (error = getSock(libPtr, s, &so))
378 goto Return;
380 error = soshutdown(so, how);
382 Return:
383 ReleaseSyscallSemaphore(libPtr);
384 API_STD_RETURN(error, 0);
385 AROS_LIBFUNC_EXIT
388 /*LONG SAVEDS setsockopt(
389 REG(d0, LONG s),
390 REG(d1, LONG level),
391 REG(d2, LONG name),
392 REG(a0, caddr_t val),
393 REG(d3, ULONG valsize),
394 REG(a6, struct SocketBase *libPtr))*/
395 AROS_LH5(LONG, setsockopt,
396 AROS_LHA(LONG, s, D0),
397 AROS_LHA(LONG, level, D1),
398 AROS_LHA(LONG, name, D2),
399 AROS_LHA(caddr_t, val, A0),
400 AROS_LHA(ULONG, valsize, D3),
401 struct SocketBase *, libPtr, 15, UL)
403 AROS_LIBFUNC_INIT
404 struct socket *so;
405 struct mbuf *m = NULL;
406 LONG error;
408 #if defined(__AROS__)
409 D(bug("[AROSTCP](amiga_syscalls.c) UL_setsockopt(%ld, 0x%08lx, 0x%08lx, %lu, %lu)\n", s, level, name, *(ULONG *)val , valsize));
410 #endif
412 CHECK_TASK();
413 DSYSCALLS(__log(LOG_DEBUG,"setsockopt(%ld, 0x%08lx, 0x%08lx, %lu, %lu) called", s, level, name, *(ULONG *)val , valsize);)
414 ObtainSyscallSemaphore(libPtr);
416 if (error = getSock(libPtr, s, &so))
417 goto Return;
418 if (valsize > MLEN) { /* unsigned catches negative values */
419 error = EINVAL;
420 goto Return;
422 if (val) {
423 m = m_get(M_WAIT, MT_SOOPTS);
424 if (m == NULL) {
425 error = ENOBUFS;
426 goto Return;
428 bcopy(val, mtod(m, caddr_t), valsize); /* aligned ? */
429 m->m_len = (int)valsize;
431 error = sosetopt(so, level, name, m);
433 Return:
434 ReleaseSyscallSemaphore(libPtr);
435 DOPTERR (if (error) __log(LOG_ERR,"setsockopt(): error %ld on option 0x%08lx, level 0x%08lx", error, name, level);)
436 API_STD_RETURN(error, 0);
437 AROS_LIBFUNC_EXIT
441 /*LONG SAVEDS getsockopt(
442 REG(d0, LONG s),
443 REG(d1, LONG level),
444 REG(d2, LONG name),
445 REG(a0, caddr_t val),
446 REG(a1, ULONG * avalsize),
447 REG(a6, struct SocketBase * libPtr))*/
448 AROS_LH5(LONG, getsockopt,
449 AROS_LHA(LONG, s, D0),
450 AROS_LHA(LONG, level, D1),
451 AROS_LHA(LONG, name, D2),
452 AROS_LHA(caddr_t, val, A0),
453 AROS_LHA(ULONG *, avalsize, A1),
454 struct SocketBase *, libPtr, 16, UL)
456 AROS_LIBFUNC_INIT
457 struct socket *so;
458 struct mbuf *m = NULL;
459 ULONG valsize, error;
461 #if defined(__AROS__)
462 D(bug("[AROSTCP](amiga_syscalls.c) UL_getsockopt(%ld, 0x%08lx, 0x%08lx)\n", s, level, name));
463 #endif
465 CHECK_TASK();
466 DSYSCALLS(__log(LOG_DEBUG,"getsockopt(%ld, 0x%08lx, 0x%08lx) called", s, level, name);)
467 ObtainSyscallSemaphore(libPtr);
469 if (error = getSock(libPtr, s, &so))
470 goto Return;
472 if (val)
473 valsize = *avalsize;
474 else
475 valsize = 0;
477 if ((error = sogetopt(so, level, name, &m)) == 0
478 && val && valsize && m != NULL) {
479 if (valsize > m->m_len) /* valsize is ULONG */
480 valsize = m->m_len;
481 bcopy(mtod(m, caddr_t), val, (u_int)valsize); /* aligned ? */
482 *avalsize = valsize;
484 if (m != NULL)
485 (void) m_free(m);
487 Return:
488 ReleaseSyscallSemaphore(libPtr);
489 DOPTERR(if (error) __log(LOG_ERR,"setsockopt(): error %ld on option 0x%08lx, level 0x%08lx", error, name, level);)
490 API_STD_RETURN(error, 0);
491 AROS_LIBFUNC_EXIT
494 /*LONG SAVEDS getsockname(
495 REG(d0, LONG fdes),
496 REG(a0, caddr_t asa),
497 REG(a1, ULONG * alen),
498 REG(a6, struct SocketBase * libPtr))*/
499 AROS_LH3(LONG, getsockname,
500 AROS_LHA(LONG, fdes, D0),
501 AROS_LHA(caddr_t, asa, A0),
502 AROS_LHA(ULONG *, alen, A1),
503 struct SocketBase *, libPtr, 17, UL)
505 AROS_LIBFUNC_INIT
506 /*register*/
507 struct socket *so;
508 struct mbuf *m;
509 LONG error;
511 #if defined(__AROS__)
512 D(bug("[AROSTCP](amiga_syscalls.c) UL_getsockname(%ld)\n", fdes));
513 #endif
515 CHECK_TASK();
516 DSYSCALLS(__log(LOG_DEBUG,"getsockname(%ld) called", fdes);)
517 ObtainSyscallSemaphore(libPtr);
519 if (error = getSock(libPtr, fdes, &so))
520 goto Return;
522 m = m_getclr(M_WAIT, MT_SONAME);
523 if (m == NULL) {
524 error = ENOBUFS;
525 goto Return;
527 if (error = (*so->so_proto->pr_usrreq)(so, PRU_SOCKADDR, 0, m, 0))
528 goto bad;
529 if (*alen > m->m_len)
530 *alen = m->m_len;
531 aligned_bcopy(mtod(m, caddr_t), (caddr_t)asa, (u_int)*alen);
533 bad:
534 m_freem(m);
536 Return:
537 ReleaseSyscallSemaphore(libPtr);
538 API_STD_RETURN(error, 0);
539 AROS_LIBFUNC_EXIT
542 /*LONG SAVEDS getpeername(
543 REG(d0, LONG fdes),
544 REG(a0, caddr_t asa),
545 REG(a1, ULONG * alen),
546 REG(a6, struct SocketBase * libPtr))*/
547 AROS_LH3(LONG, getpeername,
548 AROS_LHA(LONG, fdes, D0),
549 AROS_LHA(caddr_t, asa, A0),
550 AROS_LHA(ULONG *, alen, A1),
551 struct SocketBase *, libPtr, 18, UL)
553 AROS_LIBFUNC_INIT
554 struct socket *so;
555 struct mbuf *m;
556 LONG error;
558 #if defined(__AROS__)
559 D(bug("[AROSTCP](amiga_syscalls.c) UL_getpeername(%ld)\n", fdes));
560 #endif
562 CHECK_TASK();
563 DSYSCALLS(__log(LOG_DEBUG,"getpeername(%ld) called", fdes);)
564 ObtainSyscallSemaphore(libPtr);
566 if (error = getSock(libPtr, fdes, &so))
567 goto Return;
569 if ((so->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0) {
570 error = ENOTCONN;
571 goto Return;
574 m = m_getclr(M_WAIT, MT_SONAME);
575 if (m == NULL) {
576 error = ENOBUFS;
577 goto Return;
580 if (error = (*so->so_proto->pr_usrreq)(so, PRU_PEERADDR, 0, m, 0))
581 goto bad;
582 if (*alen > m->m_len)
583 *alen = m->m_len;
584 aligned_bcopy(mtod(m, caddr_t), (caddr_t)asa, (u_int)*alen);
586 bad:
587 m_freem(m);
589 Return:
590 ReleaseSyscallSemaphore(libPtr);
591 API_STD_RETURN(error, 0);
592 AROS_LIBFUNC_EXIT
595 LONG sockArgs(struct mbuf **mp,
596 caddr_t buf, /* aligned */
597 LONG buflen,
598 LONG type)
600 register struct mbuf *m;
601 LONG error = 0;
603 #if defined(__AROS__)
604 D(bug("[AROSTCP](amiga_syscalls.c) sockArgs()\n"));
605 #endif
607 if ((u_int)buflen > MLEN)
608 return (EINVAL);
610 m = m_get(M_WAIT, type);
611 if (m == NULL)
612 return (ENOBUFS);
613 m->m_len = buflen;
615 aligned_bcopy(buf, mtod(m, caddr_t), (u_int)buflen);
616 *mp = m;
617 if (type == MT_SONAME)
618 mtod(m, struct sockaddr *)->sa_len = buflen;
620 return (error);
624 * sdFind replaces old fdAlloc. This version now looks for free socket
625 * from socket usage bitmask stored right after descriptor table
628 LONG sdFind(struct SocketBase * libPtr, LONG *fdp)
630 int bit, moffset;
631 ULONG * smaskp;
632 int mlongs = (libPtr->dTableSize - 1) / NFDBITS + 1;
634 #if defined(__AROS__)
635 D(bug("[AROSTCP](amiga_syscalls.c) sdFind()\n"));
636 #endif
638 moffset = 0, smaskp = (ULONG *)(libPtr->dTable + libPtr->dTableSize);
639 while (mlongs) {
640 unsigned long cmask = *smaskp;
641 unsigned long dmask = cmask + 1;
643 if (dmask == 0) {
644 mlongs--, smaskp++, moffset += 32;
645 continue; /* current mask is full (cmask = 0xFFFFFFFF) */
647 cmask = ((cmask ^ dmask) >> 1) + 1; /* now only one bit set ! */
649 bit = (cmask & 0xFFFF0000)? 16: 0;
650 if (cmask & 0xFF00FF00) bit += 8;
651 if (cmask & 0xF0F0F0F0) bit += 4;
652 if (cmask & 0xCCCCCCCC) bit += 2;
653 if (cmask & 0xAAAAAAAA) bit += 1;
656 * Check if link library agrees with us on the next free fd...
658 if (libPtr->fdCallback)
659 if (AROS_UFC2(int, libPtr->fdCallback,
660 AROS_UFCA(int, moffset+bit, D0),
661 AROS_UFCA(int, FDCB_CHECK, D1)))
663 *smaskp |= cmask; /* mark this fd as used */
664 continue; /* search for the next _bit_ */
667 if (moffset + bit >= libPtr->dTableSize)
668 break;
669 else {
670 *fdp = moffset + bit;
671 return 0;
674 return (EMFILE);