2 * Copyright (C) 1993 AmiTCP/IP Group, <amitcp-group@hut.fi>
3 * Helsinki University of Technology, Finland.
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,
26 #include <sys/param.h>
27 #include <sys/systm.h>
28 #include <sys/malloc.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>
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
));
62 LONG
__socket(LONG domain
, LONG type
, LONG protocol
, struct SocketBase
*libPtr
)
68 D(bug("[AROSTCP](amiga_syscalls.c) __socket()\n"));
73 if (error
= sdFind(libPtr
, &fd
))
76 ObtainSyscallSemaphore(libPtr
);
77 error
= socreate(domain
, &so
, type
, protocol
);
78 ReleaseSyscallSemaphore(libPtr
);
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
));
89 so
->so_refcnt
= 1; /* reference count is pure AmiTCP addition */
90 libPtr
->dTable
[fd
] = so
;
92 FD_SET(fd
, (fd_set
*)(libPtr
->dTable
+ libPtr
->dTableSize
));
94 D(bug("[AROSTCP](amiga_syscalls.c) __socket: created socket 0x%p fd = %ld libPtr = 0x%p\n", so
, fd
, libPtr
));
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
)
111 #if defined(__AROS__)
112 D(bug("[AROSTCP](amiga_syscalls.c) UL_socket(%ld, %ld, %ld)\n", domain
, type
, protocol
));
115 DSYSCALLS(__log(LOG_DEBUG
,"socket(%ld, %ld, %ld) called", domain
, type
, protocol
);)
116 return __socket(domain
, type
, protocol
, libPtr
);
123 REG(a0, caddr_t name),
124 REG(d1, LONG namelen),
125 REG(a6, struct SocketBase *libPtr))*/
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
)
137 #if defined(__AROS__)
138 D(bug("[AROSTCP](amiga_syscalls.c) UL_bind(%ld, sockaddr_in, %ld)\n", s
, namelen
));
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
))
148 if (error
= sockArgs(&nam
, name
, namelen
, MT_SONAME
))
150 error
= sobind(so
, nam
);
154 ReleaseSyscallSemaphore(libPtr
);
155 API_STD_RETURN(error
, 0);
159 /*LONG SAVEDS listen(
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
)
172 #if defined(__AROS__)
173 D(bug("[AROSTCP](amiga_syscalls.c) UL_Listen(%ld, %ld)\n", s
, backlog
));
177 DSYSCALLS(__log("listen(%ld, %ld) called ", s
, backlog
);)
178 ObtainSyscallSemaphore(libPtr
);
180 if (error
= getSock(libPtr
, s
, &so
))
182 error
= solisten(so
, backlog
);
185 ReleaseSyscallSemaphore(libPtr
);
186 API_STD_RETURN(error
, 0);
190 /*LONG SAVEDS accept(
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
)
208 #if defined(__AROS__)
209 D(bug("[AROSTCP](amiga_syscalls.c) UL_accept(%ld)\n", s
));
213 DSYSCALLS(__log("accept(%ld) called", s
);)
214 ObtainSyscallSemaphore(libPtr
);
216 if (error
= getSock(libPtr
, s
, &so
))
220 if ((so
->so_options
& SO_ACCEPTCONN
) == 0) {
224 if ((so
->so_state
& SS_NBIO
) && so
->so_qlen
== 0) {
228 while (so
->so_qlen
== 0 && so
->so_error
== 0) {
229 if (so
->so_state
& SS_CANTRCVMORE
) {
230 so
->so_error
= ECONNABORTED
;
233 if (error
= tsleep(libPtr
, (caddr_t
)&so
->so_timeo
, netcon
, NULL
)) {
238 error
= so
->so_error
;
243 if (error
= sdFind(libPtr
, &fd
)) {
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
)))
257 struct socket
*aso
= so
->so_q
;
258 if (soqremque(aso
, 1) == 0)
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 */
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
);
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
);
288 LONG
__connect(LONG s
, caddr_t name
, LONG namelen
, struct SocketBase
*libPtr
)
290 /*register*/ struct socket
*so
;
295 #if defined(__AROS__)
296 D(bug("[AROSTCP](amiga_syscalls.c) __connect()\n"));
300 ObtainSyscallSemaphore(libPtr
);
302 if (error
= getSock(libPtr
, s
, &so
))
304 if ((so
->so_state
& SS_NBIO
) && (so
->so_state
& SS_ISCONNECTING
)) {
308 if (error
= sockArgs(&nam
, name
, namelen
, MT_SONAME
))
310 error
= soconnect(so
, nam
);
313 if ((so
->so_state
& SS_NBIO
) && (so
->so_state
& SS_ISCONNECTING
)) {
319 while ((so
->so_state
& SS_ISCONNECTING
) && so
->so_error
== 0)
320 if (error
= tsleep(libPtr
,(caddr_t
)&so
->so_timeo
, netcon
, NULL
))
323 error
= so
->so_error
;
328 so
->so_state
&= ~SS_ISCONNECTING
;
330 if (error
== ERESTART
)
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
)
346 #if defined(__AROS__)
347 D(bug("[AROSTCP](amiga_syscalls.c) UL_connect(%ld, sockaddr_in, %ld)\n", s
, namelen
));
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
);
356 /*LONG SAVEDS shutdown(
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
)
369 #if defined(__AROS__)
370 D(bug("[AROSTCP](amiga_syscalls.c) UL_shutdown(%ld, %ld)\n", s
, how
));
374 DSYSCALLS(__log(LOG_DEBUG
,"shutdown(%ld, %ld) called", s
, how
);)
375 ObtainSyscallSemaphore(libPtr
);
377 if (error
= getSock(libPtr
, s
, &so
))
380 error
= soshutdown(so
, how
);
383 ReleaseSyscallSemaphore(libPtr
);
384 API_STD_RETURN(error
, 0);
388 /*LONG SAVEDS setsockopt(
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
)
405 struct mbuf
*m
= NULL
;
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
));
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
))
418 if (valsize
> MLEN
) { /* unsigned catches negative values */
423 m
= m_get(M_WAIT
, MT_SOOPTS
);
428 bcopy(val
, mtod(m
, caddr_t
), valsize
); /* aligned ? */
429 m
->m_len
= (int)valsize
;
431 error
= sosetopt(so
, level
, name
, m
);
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);
441 /*LONG SAVEDS getsockopt(
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
)
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
));
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
))
477 if ((error
= sogetopt(so
, level
, name
, &m
)) == 0
478 && val
&& valsize
&& m
!= NULL
) {
479 if (valsize
> m
->m_len
) /* valsize is ULONG */
481 bcopy(mtod(m
, caddr_t
), val
, (u_int
)valsize
); /* aligned ? */
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);
494 /*LONG SAVEDS getsockname(
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
)
511 #if defined(__AROS__)
512 D(bug("[AROSTCP](amiga_syscalls.c) UL_getsockname(%ld)\n", fdes
));
516 DSYSCALLS(__log(LOG_DEBUG
,"getsockname(%ld) called", fdes
);)
517 ObtainSyscallSemaphore(libPtr
);
519 if (error
= getSock(libPtr
, fdes
, &so
))
522 m
= m_getclr(M_WAIT
, MT_SONAME
);
527 if (error
= (*so
->so_proto
->pr_usrreq
)(so
, PRU_SOCKADDR
, 0, m
, 0))
529 if (*alen
> m
->m_len
)
531 aligned_bcopy(mtod(m
, caddr_t
), (caddr_t
)asa
, (u_int
)*alen
);
537 ReleaseSyscallSemaphore(libPtr
);
538 API_STD_RETURN(error
, 0);
542 /*LONG SAVEDS getpeername(
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
)
558 #if defined(__AROS__)
559 D(bug("[AROSTCP](amiga_syscalls.c) UL_getpeername(%ld)\n", fdes
));
563 DSYSCALLS(__log(LOG_DEBUG
,"getpeername(%ld) called", fdes
);)
564 ObtainSyscallSemaphore(libPtr
);
566 if (error
= getSock(libPtr
, fdes
, &so
))
569 if ((so
->so_state
& (SS_ISCONNECTED
|SS_ISCONFIRMING
)) == 0) {
574 m
= m_getclr(M_WAIT
, MT_SONAME
);
580 if (error
= (*so
->so_proto
->pr_usrreq
)(so
, PRU_PEERADDR
, 0, m
, 0))
582 if (*alen
> m
->m_len
)
584 aligned_bcopy(mtod(m
, caddr_t
), (caddr_t
)asa
, (u_int
)*alen
);
590 ReleaseSyscallSemaphore(libPtr
);
591 API_STD_RETURN(error
, 0);
595 LONG
sockArgs(struct mbuf
**mp
,
596 caddr_t buf
, /* aligned */
600 register struct mbuf
*m
;
603 #if defined(__AROS__)
604 D(bug("[AROSTCP](amiga_syscalls.c) sockArgs()\n"));
607 if ((u_int
)buflen
> MLEN
)
610 m
= m_get(M_WAIT
, type
);
615 aligned_bcopy(buf
, mtod(m
, caddr_t
), (u_int
)buflen
);
617 if (type
== MT_SONAME
)
618 mtod(m
, struct sockaddr
*)->sa_len
= buflen
;
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
)
632 int mlongs
= (libPtr
->dTableSize
- 1) / NFDBITS
+ 1;
634 #if defined(__AROS__)
635 D(bug("[AROSTCP](amiga_syscalls.c) sdFind()\n"));
638 moffset
= 0, smaskp
= (ULONG
*)(libPtr
->dTable
+ libPtr
->dTableSize
);
640 unsigned long cmask
= *smaskp
;
641 unsigned long dmask
= cmask
+ 1;
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
)
670 *fdp
= moffset
+ bit
;