3535#include <executables/elf.h>
3636#include <heap.h>
3737#include <multitasking.h>
38+ #include <net/net.h>
3839#include <rtc.h>
3940#include <tty.h>
4041
@@ -59,6 +60,37 @@ typedef struct {
5960 uint64_t inode ;
6061} vfs_stat_info_t ;
6162
63+ #define LINUX_AF_INET 2
64+ #define LINUX_SOCK_RAW 3
65+ #define LINUX_IPPROTO_ICMP 1
66+
67+ typedef struct {
68+ uint16_t family ;
69+ uint16_t port ;
70+ uint32_t addr ;
71+ uint8_t zero [8 ];
72+ } linux_sockaddr_in_t ;
73+
74+ typedef struct {
75+ bool used ;
76+ int fd ;
77+ int domain ;
78+ int type ;
79+ int protocol ;
80+ uint8_t reply [128 ];
81+ size_t reply_len ;
82+ net_ipv4_t reply_addr ;
83+ } linux_socket_t ;
84+
85+ static linux_socket_t linux_sockets [16 ];
86+
87+ static linux_socket_t * linux_socket_by_fd (int fd ) {
88+ for (int i = 0 ; i < (int )(sizeof (linux_sockets ) / sizeof (linux_sockets [0 ])); i ++ )
89+ if (linux_sockets [i ].used && linux_sockets [i ].fd == fd )
90+ return & linux_sockets [i ];
91+ return NULL ;
92+ }
93+
6294// char current_exec_path[256] = "/";
6395uint64_t current_fs_base = 0 ;
6496uint32_t current_umask = 022 ;
@@ -781,6 +813,10 @@ static uint64 sys_close(uint64_t fd) {
781813 if (!fd_valid ((int )fd ))
782814 return - LINUX_EBADF ;
783815
816+ linux_socket_t * sock = linux_socket_by_fd ((int )fd );
817+ if (sock )
818+ memset (sock , 0 , sizeof (* sock ));
819+
784820 return fd_close ((int )fd ) == 0 ? 0 : - LINUX_EBADF ;
785821}
786822
@@ -909,14 +945,32 @@ static uint64 sys_writev(uint64_t fd, const linux_iovec_t *iov, uint64_t iovcnt)
909945}
910946
911947static uint64 sys_socket (uint64_t domain , uint64_t type , uint64_t protocol ) {
912- (void )type ;
913- (void )protocol ;
914-
915- // Networking stack is not exposed through Linux sockets yet.
916- // Return Linux-like "address family not supported" instead of a fake fd.
917- if (domain == 1 || domain == 2 || domain == 10 )
948+ if (domain != LINUX_AF_INET )
918949 return - LINUX_EAFNOSUPPORT ;
919- return - LINUX_EAFNOSUPPORT ;
950+ if (type != LINUX_SOCK_RAW || protocol != LINUX_IPPROTO_ICMP )
951+ return - LINUX_EPROTONOSUPPORT ;
952+
953+ linux_socket_t * sock = NULL ;
954+ for (int i = 0 ; i < (int )(sizeof (linux_sockets ) / sizeof (linux_sockets [0 ])); i ++ ) {
955+ if (!linux_sockets [i ].used ) {
956+ sock = & linux_sockets [i ];
957+ break ;
958+ }
959+ }
960+ if (!sock )
961+ return - LINUX_ENFILE ;
962+
963+ int fd = fd_create_virtual ("/dev/socket/icmp" , VFS_RDWR );
964+ if (fd < 0 )
965+ return - LINUX_ENFILE ;
966+
967+ memset (sock , 0 , sizeof (* sock ));
968+ sock -> used = true;
969+ sock -> fd = fd ;
970+ sock -> domain = (int )domain ;
971+ sock -> type = (int )type ;
972+ sock -> protocol = (int )protocol ;
973+ return fd ;
920974}
921975
922976static uint64 sys_connect (uint64_t fd , const void * addr , uint64_t addrlen ) {
@@ -928,6 +982,84 @@ static uint64 sys_connect(uint64_t fd, const void *addr, uint64_t addrlen) {
928982 return - LINUX_ENOTSOCK ;
929983}
930984
985+ static uint64 sys_sendto (uint64_t fd , const void * buf , uint64_t len , uint64_t flags ,
986+ const void * addr , uint64_t addrlen ) {
987+ (void )flags ;
988+ linux_socket_t * sock = linux_socket_by_fd ((int )fd );
989+ if (!sock )
990+ return fd_valid ((int )fd ) ? - LINUX_ENOTSOCK : - LINUX_EBADF ;
991+ if (!buf || !addr || addrlen < sizeof (linux_sockaddr_in_t ))
992+ return - LINUX_EINVAL ;
993+
994+ const linux_sockaddr_in_t * in = (const linux_sockaddr_in_t * )addr ;
995+ if (in -> family != LINUX_AF_INET )
996+ return - LINUX_EAFNOSUPPORT ;
997+
998+ net_ipv4_t dst = net_ntohl (in -> addr );
999+ uint16_t id = 0x4242 ;
1000+ uint16_t seq = 0 ;
1001+ if (len >= 8 ) {
1002+ const uint8_t * icmp = (const uint8_t * )buf ;
1003+ id = ((uint16_t )icmp [4 ] << 8 ) | icmp [5 ];
1004+ seq = ((uint16_t )icmp [6 ] << 8 ) | icmp [7 ];
1005+ }
1006+
1007+ int r = icmp_ping (dst , id , seq , 500000 );
1008+ if (r != NET_OK )
1009+ return - LINUX_ETIMEDOUT ;
1010+
1011+ sock -> reply_addr = dst ;
1012+ sock -> reply_len = len < sizeof (sock -> reply ) ? len : sizeof (sock -> reply );
1013+ memcpy (sock -> reply , buf , sock -> reply_len );
1014+ if (sock -> reply_len >= 1 )
1015+ sock -> reply [0 ] = 0 ; /* echo reply */
1016+ if (sock -> reply_len >= 4 ) {
1017+ sock -> reply [2 ] = 0 ;
1018+ sock -> reply [3 ] = 0 ;
1019+ uint16_t sum = net_checksum (sock -> reply , sock -> reply_len );
1020+ sock -> reply [2 ] = (uint8_t )(sum >> 8 );
1021+ sock -> reply [3 ] = (uint8_t )sum ;
1022+ }
1023+ return len ;
1024+ }
1025+
1026+ static uint64 sys_recvfrom (uint64_t fd , void * buf , uint64_t len , uint64_t flags ,
1027+ void * addr , uint64_t * addrlen ) {
1028+ (void )flags ;
1029+ linux_socket_t * sock = linux_socket_by_fd ((int )fd );
1030+ if (!sock )
1031+ return fd_valid ((int )fd ) ? - LINUX_ENOTSOCK : - LINUX_EBADF ;
1032+ if (!buf )
1033+ return - LINUX_EINVAL ;
1034+ if (!sock -> reply_len )
1035+ return - LINUX_EAGAIN ;
1036+
1037+ size_t n = sock -> reply_len < len ? sock -> reply_len : len ;
1038+ memcpy (buf , sock -> reply , n );
1039+ sock -> reply_len = 0 ;
1040+
1041+ if (addr && addrlen && * addrlen >= sizeof (linux_sockaddr_in_t )) {
1042+ linux_sockaddr_in_t * in = (linux_sockaddr_in_t * )addr ;
1043+ memset (in , 0 , sizeof (* in ));
1044+ in -> family = LINUX_AF_INET ;
1045+ in -> addr = net_htonl (sock -> reply_addr );
1046+ * addrlen = sizeof (* in );
1047+ }
1048+ return n ;
1049+ }
1050+
1051+ static uint64 sys_setsockopt (uint64_t fd , uint64_t level , uint64_t optname ,
1052+ const void * optval , uint64_t optlen ) {
1053+ (void )level ;
1054+ (void )optname ;
1055+ (void )optval ;
1056+ (void )optlen ;
1057+ linux_socket_t * sock = linux_socket_by_fd ((int )fd );
1058+ if (!sock )
1059+ return fd_valid ((int )fd ) ? - LINUX_ENOTSOCK : - LINUX_EBADF ;
1060+ return 0 ;
1061+ }
1062+
9311063static uint64 sys_ioctl (uint64_t fd , uint64_t req , uint64_t arg ) {
9321064 if (!fd_valid ((int )fd ))
9331065 return - LINUX_EBADF ;
@@ -1679,6 +1811,11 @@ static const char *names[] = {
16791811 [1 ] = "write" ,
16801812 [2 ] = "open" ,
16811813 [3 ] = "close" ,
1814+ [41 ] = "socket" ,
1815+ [42 ] = "connect" ,
1816+ [44 ] = "sendto" ,
1817+ [45 ] = "recvfrom" ,
1818+ [54 ] = "setsockopt" ,
16821819 [9 ] = "mmap" ,
16831820 [11 ] = "munmap" ,
16841821 [12 ] = "brk" ,
@@ -1792,6 +1929,15 @@ uint64_t syscall_dispatch(
17921929 case LINUX_SYS_CONNECT :
17931930 return sys_connect (arg1 , (const void * )arg2 , arg3 );
17941931
1932+ case LINUX_SYS_SENDTO :
1933+ return sys_sendto (arg1 , (const void * )arg2 , arg3 , arg4 , (const void * )arg5 , arg6 );
1934+
1935+ case LINUX_SYS_RECVFROM :
1936+ return sys_recvfrom (arg1 , (void * )arg2 , arg3 , arg4 , (void * )arg5 , (uint64_t * )arg6 );
1937+
1938+ case LINUX_SYS_SETSOCKOPT :
1939+ return sys_setsockopt (arg1 , arg2 , arg3 , (const void * )arg4 , arg5 );
1940+
17951941 case LINUX_SYS_CLONE :
17961942 return sys_fork ();
17971943
@@ -1934,4 +2080,4 @@ uint64_t syscall_dispatch(
19342080 printf (linux_syscalls_prefix "Unknown, returning -ENOSYS for (%u)" , nr );
19352081 return - LINUX_ENOSYS ;
19362082 }
1937- }
2083+ }
0 commit comments