mirror of
https://github.com/RGBCube/serenity
synced 2025-05-28 09:55:06 +00:00
Kernel+LibC+Userland: Start working on an IPv4 socket backend.
The first userland networking program will be "ping" :^)
This commit is contained in:
parent
8e667747f0
commit
a017a77442
23 changed files with 374 additions and 3 deletions
|
@ -28,7 +28,6 @@ public:
|
||||||
m_data[2] = c;
|
m_data[2] = c;
|
||||||
m_data[3] = d;
|
m_data[3] = d;
|
||||||
}
|
}
|
||||||
~IPv4Address() { }
|
|
||||||
|
|
||||||
byte operator[](int i) const
|
byte operator[](int i) const
|
||||||
{
|
{
|
||||||
|
|
111
Kernel/IPv4Socket.cpp
Normal file
111
Kernel/IPv4Socket.cpp
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
#include <Kernel/IPv4Socket.h>
|
||||||
|
#include <Kernel/UnixTypes.h>
|
||||||
|
#include <Kernel/Process.h>
|
||||||
|
#include <Kernel/NetworkAdapter.h>
|
||||||
|
#include <LibC/errno_numbers.h>
|
||||||
|
|
||||||
|
Retained<IPv4Socket> IPv4Socket::create(int type, int protocol)
|
||||||
|
{
|
||||||
|
return adopt(*new IPv4Socket(type, protocol));
|
||||||
|
}
|
||||||
|
|
||||||
|
IPv4Socket::IPv4Socket(int type, int protocol)
|
||||||
|
: Socket(AF_INET, type, protocol)
|
||||||
|
{
|
||||||
|
kprintf("%s(%u) IPv4Socket{%p} created with type=%u\n", current->name().characters(), current->pid(), this, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
IPv4Socket::~IPv4Socket()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IPv4Socket::get_address(sockaddr* address, socklen_t* address_size)
|
||||||
|
{
|
||||||
|
// FIXME: Look into what fallback behavior we should have here.
|
||||||
|
if (*address_size != sizeof(sockaddr_in))
|
||||||
|
return false;
|
||||||
|
memcpy(address, &m_peer_address, sizeof(sockaddr_in));
|
||||||
|
*address_size = sizeof(sockaddr_in);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
KResult IPv4Socket::bind(const sockaddr* address, socklen_t address_size)
|
||||||
|
{
|
||||||
|
ASSERT(!is_connected());
|
||||||
|
if (address_size != sizeof(sockaddr_in))
|
||||||
|
return KResult(-EINVAL);
|
||||||
|
if (address->sa_family != AF_INET)
|
||||||
|
return KResult(-EINVAL);
|
||||||
|
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
|
KResult IPv4Socket::connect(const sockaddr* address, socklen_t address_size)
|
||||||
|
{
|
||||||
|
ASSERT(!m_bound);
|
||||||
|
if (address_size != sizeof(sockaddr_in))
|
||||||
|
return KResult(-EINVAL);
|
||||||
|
if (address->sa_family != AF_INET)
|
||||||
|
return KResult(-EINVAL);
|
||||||
|
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
|
void IPv4Socket::attach_fd(SocketRole)
|
||||||
|
{
|
||||||
|
++m_attached_fds;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IPv4Socket::detach_fd(SocketRole)
|
||||||
|
{
|
||||||
|
--m_attached_fds;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IPv4Socket::can_read(SocketRole) const
|
||||||
|
{
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t IPv4Socket::read(SocketRole role, byte* buffer, ssize_t size)
|
||||||
|
{
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t IPv4Socket::write(SocketRole role, const byte* data, ssize_t size)
|
||||||
|
{
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IPv4Socket::can_write(SocketRole role) const
|
||||||
|
{
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t IPv4Socket::sendto(const void* data, size_t data_length, int flags, const sockaddr* addr, socklen_t addr_length)
|
||||||
|
{
|
||||||
|
(void)flags;
|
||||||
|
ASSERT(data_length);
|
||||||
|
if (addr_length != sizeof(sockaddr_in))
|
||||||
|
return -EINVAL;
|
||||||
|
// FIXME: Find the adapter some better way!
|
||||||
|
auto* adapter = NetworkAdapter::from_ipv4_address(IPv4Address(192, 168, 5, 2));
|
||||||
|
if (!adapter) {
|
||||||
|
// FIXME: Figure out which error code to return.
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addr->sa_family != AF_INET) {
|
||||||
|
kprintf("sendto: Bad address family: %u is not AF_INET!\n", addr->sa_family);
|
||||||
|
return -EAFNOSUPPORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto peer_address = IPv4Address((const byte*)&((const sockaddr_in*)addr)->sin_addr.s_addr);
|
||||||
|
|
||||||
|
kprintf("sendto: peer_address=%s\n", peer_address.to_string().characters());
|
||||||
|
|
||||||
|
// FIXME: If we can't find the right MAC address, block until it's available?
|
||||||
|
// I feel like this should happen in a layer below this code.
|
||||||
|
MACAddress mac_address;
|
||||||
|
adapter->send_ipv4(mac_address, peer_address, (IPv4Protocol)protocol(), ByteBuffer::copy((const byte*)data, data_length));
|
||||||
|
return data_length;
|
||||||
|
}
|
34
Kernel/IPv4Socket.h
Normal file
34
Kernel/IPv4Socket.h
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Kernel/Socket.h>
|
||||||
|
#include <Kernel/DoubleBuffer.h>
|
||||||
|
#include <Kernel/IPv4.h>
|
||||||
|
|
||||||
|
class IPv4Socket final : public Socket {
|
||||||
|
public:
|
||||||
|
static Retained<IPv4Socket> create(int type, int protocol);
|
||||||
|
virtual ~IPv4Socket() override;
|
||||||
|
|
||||||
|
virtual KResult bind(const sockaddr*, socklen_t) override;
|
||||||
|
virtual KResult connect(const sockaddr*, socklen_t) override;
|
||||||
|
virtual bool get_address(sockaddr*, socklen_t*) override;
|
||||||
|
virtual void attach_fd(SocketRole) override;
|
||||||
|
virtual void detach_fd(SocketRole) override;
|
||||||
|
virtual bool can_read(SocketRole) const override;
|
||||||
|
virtual ssize_t read(SocketRole, byte*, ssize_t) override;
|
||||||
|
virtual ssize_t write(SocketRole, const byte*, ssize_t) override;
|
||||||
|
virtual bool can_write(SocketRole) const override;
|
||||||
|
virtual ssize_t sendto(const void*, size_t, int, const sockaddr*, socklen_t) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
IPv4Socket(int type, int protocol);
|
||||||
|
virtual bool is_ipv4() const override { return true; }
|
||||||
|
|
||||||
|
bool m_bound { false };
|
||||||
|
int m_attached_fds { 0 };
|
||||||
|
IPv4Address m_peer_address;
|
||||||
|
|
||||||
|
DoubleBuffer m_for_client;
|
||||||
|
DoubleBuffer m_for_server;
|
||||||
|
};
|
||||||
|
|
|
@ -163,3 +163,8 @@ bool LocalSocket::can_write(SocketRole role) const
|
||||||
return !m_accepted_fds_open || m_for_server.bytes_in_write_buffer() < 4096;
|
return !m_accepted_fds_open || m_for_server.bytes_in_write_buffer() < 4096;
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t LocalSocket::sendto(const void*, size_t, int, const sockaddr*, socklen_t)
|
||||||
|
{
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ public:
|
||||||
virtual ssize_t read(SocketRole, byte*, ssize_t) override;
|
virtual ssize_t read(SocketRole, byte*, ssize_t) override;
|
||||||
virtual ssize_t write(SocketRole, const byte*, ssize_t) override;
|
virtual ssize_t write(SocketRole, const byte*, ssize_t) override;
|
||||||
virtual bool can_write(SocketRole) const override;
|
virtual bool can_write(SocketRole) const override;
|
||||||
|
virtual ssize_t sendto(const void*, size_t, int, const sockaddr*, socklen_t) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit LocalSocket(int type);
|
explicit LocalSocket(int type);
|
||||||
|
|
|
@ -34,6 +34,7 @@ KERNEL_OBJS = \
|
||||||
PS2MouseDevice.o \
|
PS2MouseDevice.o \
|
||||||
Socket.o \
|
Socket.o \
|
||||||
LocalSocket.o \
|
LocalSocket.o \
|
||||||
|
IPv4Socket.o \
|
||||||
NetworkAdapter.o \
|
NetworkAdapter.o \
|
||||||
E1000NetworkAdapter.o \
|
E1000NetworkAdapter.o \
|
||||||
NetworkTask.o
|
NetworkTask.o
|
||||||
|
|
|
@ -2515,6 +2515,32 @@ KResult Process::wait_for_connect(Socket& socket)
|
||||||
return KSuccess;
|
return KSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t Process::sys$sendto(const Syscall::SC_sendto_params* params)
|
||||||
|
{
|
||||||
|
if (!validate_read_typed(params))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
int sockfd = params->sockfd;
|
||||||
|
const void* data = params->data;
|
||||||
|
size_t data_length = params->data_length;
|
||||||
|
int flags = params->flags;
|
||||||
|
auto* addr = (const sockaddr*)params->addr;
|
||||||
|
auto addr_length = (socklen_t)params->addr_length;
|
||||||
|
|
||||||
|
if (!validate_read(data, data_length))
|
||||||
|
return -EFAULT;
|
||||||
|
if (!validate_read(addr, addr_length))
|
||||||
|
return -EFAULT;
|
||||||
|
auto* descriptor = file_descriptor(sockfd);
|
||||||
|
if (!descriptor)
|
||||||
|
return -EBADF;
|
||||||
|
if (!descriptor->is_socket())
|
||||||
|
return -ENOTSOCK;
|
||||||
|
auto& socket = *descriptor->socket();
|
||||||
|
kprintf("sendto %p (%u), flags=%u, addr: %p (%u)\n", data, data_length, flags, addr, addr_length);
|
||||||
|
return socket.sendto(data, data_length, flags, addr, addr_length);
|
||||||
|
}
|
||||||
|
|
||||||
struct SharedBuffer {
|
struct SharedBuffer {
|
||||||
SharedBuffer(pid_t pid1, pid_t pid2, int size)
|
SharedBuffer(pid_t pid1, pid_t pid2, int size)
|
||||||
: m_pid1(pid1)
|
: m_pid1(pid1)
|
||||||
|
|
|
@ -230,6 +230,7 @@ public:
|
||||||
int sys$listen(int sockfd, int backlog);
|
int sys$listen(int sockfd, int backlog);
|
||||||
int sys$accept(int sockfd, sockaddr*, socklen_t*);
|
int sys$accept(int sockfd, sockaddr*, socklen_t*);
|
||||||
int sys$connect(int sockfd, const sockaddr*, socklen_t);
|
int sys$connect(int sockfd, const sockaddr*, socklen_t);
|
||||||
|
ssize_t sys$sendto(const Syscall::SC_sendto_params*);
|
||||||
int sys$restore_signal_mask(dword mask);
|
int sys$restore_signal_mask(dword mask);
|
||||||
|
|
||||||
int sys$create_shared_buffer(pid_t peer_pid, int, void** buffer);
|
int sys$create_shared_buffer(pid_t peer_pid, int, void** buffer);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include <Kernel/Socket.h>
|
#include <Kernel/Socket.h>
|
||||||
#include <Kernel/LocalSocket.h>
|
#include <Kernel/LocalSocket.h>
|
||||||
|
#include <Kernel/IPv4Socket.h>
|
||||||
#include <Kernel/UnixTypes.h>
|
#include <Kernel/UnixTypes.h>
|
||||||
#include <Kernel/Process.h>
|
#include <Kernel/Process.h>
|
||||||
#include <LibC/errno_numbers.h>
|
#include <LibC/errno_numbers.h>
|
||||||
|
@ -10,6 +11,8 @@ KResultOr<Retained<Socket>> Socket::create(int domain, int type, int protocol)
|
||||||
switch (domain) {
|
switch (domain) {
|
||||||
case AF_LOCAL:
|
case AF_LOCAL:
|
||||||
return LocalSocket::create(type & SOCK_TYPE_MASK);
|
return LocalSocket::create(type & SOCK_TYPE_MASK);
|
||||||
|
case AF_INET:
|
||||||
|
return IPv4Socket::create(type & SOCK_TYPE_MASK, protocol);
|
||||||
default:
|
default:
|
||||||
return KResult(-EAFNOSUPPORT);
|
return KResult(-EAFNOSUPPORT);
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,12 +28,14 @@ public:
|
||||||
virtual KResult connect(const sockaddr*, socklen_t) = 0;
|
virtual KResult connect(const sockaddr*, socklen_t) = 0;
|
||||||
virtual bool get_address(sockaddr*, socklen_t*) = 0;
|
virtual bool get_address(sockaddr*, socklen_t*) = 0;
|
||||||
virtual bool is_local() const { return false; }
|
virtual bool is_local() const { return false; }
|
||||||
|
virtual bool is_ipv4() const { return false; }
|
||||||
virtual void attach_fd(SocketRole) = 0;
|
virtual void attach_fd(SocketRole) = 0;
|
||||||
virtual void detach_fd(SocketRole) = 0;
|
virtual void detach_fd(SocketRole) = 0;
|
||||||
virtual bool can_read(SocketRole) const = 0;
|
virtual bool can_read(SocketRole) const = 0;
|
||||||
virtual ssize_t read(SocketRole, byte*, ssize_t) = 0;
|
virtual ssize_t read(SocketRole, byte*, ssize_t) = 0;
|
||||||
virtual ssize_t write(SocketRole, const byte*, ssize_t) = 0;
|
virtual ssize_t write(SocketRole, const byte*, ssize_t) = 0;
|
||||||
virtual bool can_write(SocketRole) const = 0;
|
virtual bool can_write(SocketRole) const = 0;
|
||||||
|
virtual ssize_t sendto(const void*, size_t, int flags, const sockaddr*, socklen_t) = 0;
|
||||||
|
|
||||||
pid_t origin_pid() const { return m_origin_pid; }
|
pid_t origin_pid() const { return m_origin_pid; }
|
||||||
|
|
||||||
|
|
|
@ -227,6 +227,8 @@ static dword handle(RegisterDump& regs, dword function, dword arg1, dword arg2,
|
||||||
return current->sys$seal_shared_buffer((int)arg1);
|
return current->sys$seal_shared_buffer((int)arg1);
|
||||||
case Syscall::SC_get_shared_buffer_size:
|
case Syscall::SC_get_shared_buffer_size:
|
||||||
return current->sys$get_shared_buffer_size((int)arg1);
|
return current->sys$get_shared_buffer_size((int)arg1);
|
||||||
|
case Syscall::SC_sendto:
|
||||||
|
return current->sys$sendto((const SC_sendto_params*)arg1);
|
||||||
default:
|
default:
|
||||||
kprintf("<%u> int0x82: Unknown function %u requested {%x, %x, %x}\n", current->pid(), function, arg1, arg2, arg3);
|
kprintf("<%u> int0x82: Unknown function %u requested {%x, %x, %x}\n", current->pid(), function, arg1, arg2, arg3);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -88,6 +88,7 @@
|
||||||
__ENUMERATE_SYSCALL(restore_signal_mask) \
|
__ENUMERATE_SYSCALL(restore_signal_mask) \
|
||||||
__ENUMERATE_SYSCALL(get_shared_buffer_size) \
|
__ENUMERATE_SYSCALL(get_shared_buffer_size) \
|
||||||
__ENUMERATE_SYSCALL(seal_shared_buffer) \
|
__ENUMERATE_SYSCALL(seal_shared_buffer) \
|
||||||
|
__ENUMERATE_SYSCALL(sendto) \
|
||||||
|
|
||||||
|
|
||||||
namespace Syscall {
|
namespace Syscall {
|
||||||
|
@ -128,6 +129,15 @@ struct SC_select_params {
|
||||||
struct timeval* timeout;
|
struct timeval* timeout;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SC_sendto_params {
|
||||||
|
int sockfd;
|
||||||
|
const void* data;
|
||||||
|
size_t data_length;
|
||||||
|
int flags;
|
||||||
|
const void* addr; // const sockaddr*
|
||||||
|
size_t addr_length; // socklen_t
|
||||||
|
};
|
||||||
|
|
||||||
void initialize();
|
void initialize();
|
||||||
int sync();
|
int sync();
|
||||||
|
|
||||||
|
|
|
@ -315,12 +315,20 @@ struct pollfd {
|
||||||
#define AF_MASK 0xff
|
#define AF_MASK 0xff
|
||||||
#define AF_UNSPEC 0
|
#define AF_UNSPEC 0
|
||||||
#define AF_LOCAL 1
|
#define AF_LOCAL 1
|
||||||
|
#define AF_INET 2
|
||||||
|
#define PF_LOCAL AF_LOCAL
|
||||||
|
#define PF_INET AF_INET
|
||||||
|
|
||||||
#define SOCK_TYPE_MASK 0xff
|
#define SOCK_TYPE_MASK 0xff
|
||||||
#define SOCK_STREAM 1
|
#define SOCK_STREAM 1
|
||||||
|
#define SOCK_RAW 3
|
||||||
#define SOCK_NONBLOCK 04000
|
#define SOCK_NONBLOCK 04000
|
||||||
#define SOCK_CLOEXEC 02000000
|
#define SOCK_CLOEXEC 02000000
|
||||||
|
|
||||||
|
#define IPPROTO_ICMP 1
|
||||||
|
#define IPPROTO_TCP 6
|
||||||
|
#define IPPROTO_UDP 17
|
||||||
|
|
||||||
struct sockaddr {
|
struct sockaddr {
|
||||||
word sa_family;
|
word sa_family;
|
||||||
char sa_data[14];
|
char sa_data[14];
|
||||||
|
@ -333,3 +341,14 @@ struct sockaddr_un {
|
||||||
word sun_family;
|
word sun_family;
|
||||||
char sun_path[UNIX_PATH_MAX];
|
char sun_path[UNIX_PATH_MAX];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct in_addr {
|
||||||
|
uint32_t s_addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sockaddr_in {
|
||||||
|
int16_t sin_family;
|
||||||
|
uint16_t sin_port;
|
||||||
|
struct in_addr sin_addr;
|
||||||
|
char sin_zero[8];
|
||||||
|
};
|
||||||
|
|
|
@ -74,6 +74,7 @@ cp -v ../Userland/df mnt/bin/df
|
||||||
cp -v ../Userland/su mnt/bin/su
|
cp -v ../Userland/su mnt/bin/su
|
||||||
cp -v ../Userland/env mnt/bin/env
|
cp -v ../Userland/env mnt/bin/env
|
||||||
cp -v ../Userland/stat mnt/bin/stat
|
cp -v ../Userland/stat mnt/bin/stat
|
||||||
|
cp -v ../Userland/ping mnt/bin/ping
|
||||||
chmod 4755 mnt/bin/su
|
chmod 4755 mnt/bin/su
|
||||||
cp -v ../Applications/Terminal/Terminal mnt/bin/Terminal
|
cp -v ../Applications/Terminal/Terminal mnt/bin/Terminal
|
||||||
cp -v ../Applications/FontEditor/FontEditor mnt/bin/FontEditor
|
cp -v ../Applications/FontEditor/FontEditor mnt/bin/FontEditor
|
||||||
|
|
|
@ -39,6 +39,7 @@ LIBC_OBJS = \
|
||||||
sys/wait.o \
|
sys/wait.o \
|
||||||
poll.o \
|
poll.o \
|
||||||
locale.o \
|
locale.o \
|
||||||
|
arpa/inet.o \
|
||||||
crt0.o
|
crt0.o
|
||||||
|
|
||||||
ASM_OBJS = setjmp.no
|
ASM_OBJS = setjmp.no
|
||||||
|
|
19
LibC/arpa/inet.cpp
Normal file
19
LibC/arpa/inet.cpp
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
const char* inet_ntop(int af, const void* src, char* dst, socklen_t len)
|
||||||
|
{
|
||||||
|
if (af != AF_INET) {
|
||||||
|
errno = EAFNOSUPPORT;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
auto* bytes = (const unsigned char*)src;
|
||||||
|
snprintf(dst, len, "%u.%u.%u.%u", bytes[3], bytes[2], bytes[1], bytes[0]);
|
||||||
|
return (const char*)dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
22
LibC/arpa/inet.h
Normal file
22
LibC/arpa/inet.h
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
|
||||||
|
__BEGIN_DECLS
|
||||||
|
|
||||||
|
const char* inet_ntop(int af, const void* src, char* dst, socklen_t);
|
||||||
|
|
||||||
|
static inline uint16_t htons(uint16_t hs)
|
||||||
|
{
|
||||||
|
uint8_t* s = (uint8_t*)&hs;
|
||||||
|
return (uint16_t)(s[0] << 8 | s[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint16_t ntohs(uint16_t ns)
|
||||||
|
{
|
||||||
|
return htons(ns);
|
||||||
|
}
|
||||||
|
|
||||||
|
__END_DECLS
|
||||||
|
|
22
LibC/netinet/ip_icmp.h
Normal file
22
LibC/netinet/ip_icmp.h
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
__BEGIN_DECLS
|
||||||
|
|
||||||
|
struct icmphdr {
|
||||||
|
uint8_t type;
|
||||||
|
uint8_t code;
|
||||||
|
uint16_t checksum;
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
uint16_t id;
|
||||||
|
uint16_t sequence;
|
||||||
|
} echo;
|
||||||
|
uint32_t gateway;
|
||||||
|
} un;
|
||||||
|
};
|
||||||
|
|
||||||
|
__END_DECLS
|
||||||
|
|
|
@ -34,5 +34,12 @@ int connect(int sockfd, const sockaddr* addr, socklen_t addrlen)
|
||||||
__RETURN_WITH_ERRNO(rc, rc, -1);
|
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t sendto(int sockfd, const void* data, size_t data_length, int flags, const struct sockaddr* addr, socklen_t addr_length)
|
||||||
|
{
|
||||||
|
Syscall::SC_sendto_params params { sockfd, data, data_length, flags, addr, addr_length };
|
||||||
|
int rc = syscall(SC_sendto, ¶ms);
|
||||||
|
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,34 +2,55 @@
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
__BEGIN_DECLS
|
__BEGIN_DECLS
|
||||||
|
|
||||||
#define AF_MASK 0xff
|
#define AF_MASK 0xff
|
||||||
#define AF_UNSPEC 0
|
#define AF_UNSPEC 0
|
||||||
#define AF_LOCAL 1
|
#define AF_LOCAL 1
|
||||||
|
#define AF_INET 2
|
||||||
|
#define PF_LOCAL AF_LOCAL
|
||||||
|
#define PF_INET AF_INET
|
||||||
|
|
||||||
#define SOCK_TYPE_MASK 0xff
|
#define SOCK_TYPE_MASK 0xff
|
||||||
#define SOCK_STREAM 1
|
#define SOCK_STREAM 1
|
||||||
|
#define SOCK_RAW 3
|
||||||
#define SOCK_NONBLOCK 04000
|
#define SOCK_NONBLOCK 04000
|
||||||
#define SOCK_CLOEXEC 02000000
|
#define SOCK_CLOEXEC 02000000
|
||||||
|
|
||||||
|
#define IPPROTO_ICMP 1
|
||||||
|
#define IPPROTO_TCP 6
|
||||||
|
#define IPPROTO_UDP 17
|
||||||
|
|
||||||
struct sockaddr {
|
struct sockaddr {
|
||||||
unsigned short sa_family;
|
uint16_t sa_family;
|
||||||
char sa_data[14];
|
char sa_data[14];
|
||||||
};
|
};
|
||||||
|
|
||||||
#define UNIX_PATH_MAX 108
|
#define UNIX_PATH_MAX 108
|
||||||
struct sockaddr_un {
|
struct sockaddr_un {
|
||||||
unsigned short sun_family;
|
uint16_t sun_family;
|
||||||
char sun_path[UNIX_PATH_MAX];
|
char sun_path[UNIX_PATH_MAX];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct in_addr {
|
||||||
|
uint32_t s_addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sockaddr_in {
|
||||||
|
uint16_t sin_family;
|
||||||
|
uint16_t sin_port;
|
||||||
|
struct in_addr sin_addr;
|
||||||
|
char sin_zero[8];
|
||||||
|
};
|
||||||
|
|
||||||
int socket(int domain, int type, int protocol);
|
int socket(int domain, int type, int protocol);
|
||||||
int bind(int sockfd, const sockaddr* addr, socklen_t);
|
int bind(int sockfd, const sockaddr* addr, socklen_t);
|
||||||
int listen(int sockfd, int backlog);
|
int listen(int sockfd, int backlog);
|
||||||
int accept(int sockfd, sockaddr*, socklen_t*);
|
int accept(int sockfd, sockaddr*, socklen_t*);
|
||||||
int connect(int sockfd, const sockaddr*, socklen_t);
|
int connect(int sockfd, const sockaddr*, socklen_t);
|
||||||
|
ssize_t sendto(int sockfd, const void*, size_t, int flags, const struct sockaddr*, socklen_t);
|
||||||
|
|
||||||
__END_DECLS
|
__END_DECLS
|
||||||
|
|
||||||
|
|
1
Userland/.gitignore
vendored
1
Userland/.gitignore
vendored
|
@ -37,3 +37,4 @@ su
|
||||||
env
|
env
|
||||||
chown
|
chown
|
||||||
stat
|
stat
|
||||||
|
ping
|
||||||
|
|
|
@ -33,6 +33,7 @@ OBJS = \
|
||||||
su.o \
|
su.o \
|
||||||
env.o \
|
env.o \
|
||||||
stat.o \
|
stat.o \
|
||||||
|
ping.o \
|
||||||
rm.o
|
rm.o
|
||||||
|
|
||||||
APPS = \
|
APPS = \
|
||||||
|
@ -71,6 +72,7 @@ APPS = \
|
||||||
su \
|
su \
|
||||||
env \
|
env \
|
||||||
stat \
|
stat \
|
||||||
|
ping \
|
||||||
rm
|
rm
|
||||||
|
|
||||||
ARCH_FLAGS =
|
ARCH_FLAGS =
|
||||||
|
@ -198,6 +200,9 @@ env: env.o
|
||||||
stat: stat.o
|
stat: stat.o
|
||||||
$(LD) -o $@ $(LDFLAGS) $< -lc
|
$(LD) -o $@ $(LDFLAGS) $< -lc
|
||||||
|
|
||||||
|
ping: ping.o
|
||||||
|
$(LD) -o $@ $(LDFLAGS) $< -lc
|
||||||
|
|
||||||
.cpp.o:
|
.cpp.o:
|
||||||
@echo "CXX $<"; $(CXX) $(CXXFLAGS) -o $@ -c $<
|
@echo "CXX $<"; $(CXX) $(CXXFLAGS) -o $@ -c $<
|
||||||
|
|
||||||
|
|
58
Userland/ping.cpp
Normal file
58
Userland/ping.cpp
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <netinet/ip_icmp.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <Kernel/NetworkOrdered.h>
|
||||||
|
|
||||||
|
NetworkOrdered<word> internet_checksum(const void* ptr, size_t count)
|
||||||
|
{
|
||||||
|
dword checksum = 0;
|
||||||
|
auto* w = (const word*)ptr;
|
||||||
|
while (count > 1) {
|
||||||
|
checksum += convert_between_host_and_network(*w++);
|
||||||
|
if (checksum & 0x80000000)
|
||||||
|
checksum = (checksum & 0xffff) | (checksum >> 16);
|
||||||
|
count -= 2;
|
||||||
|
}
|
||||||
|
while (checksum >> 16)
|
||||||
|
checksum = (checksum & 0xffff) + (checksum >> 16);
|
||||||
|
return ~checksum & 0xffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
int fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
|
||||||
|
if (fd < 0) {
|
||||||
|
perror("socket");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sockaddr_in peer_address;
|
||||||
|
memset(&peer_address, 0, sizeof(peer_address));
|
||||||
|
peer_address.sin_family = AF_INET;
|
||||||
|
peer_address.sin_port = 0;
|
||||||
|
peer_address.sin_addr.s_addr = 0x0105a8c0; // 192.168.5.1
|
||||||
|
|
||||||
|
struct PingPacket {
|
||||||
|
struct icmphdr header;
|
||||||
|
char msg[64 - sizeof(struct icmphdr)];
|
||||||
|
};
|
||||||
|
|
||||||
|
PingPacket ping_packet;
|
||||||
|
memset(&ping_packet, 0, sizeof(PingPacket));
|
||||||
|
|
||||||
|
ping_packet.header.type = 8; // Echo request
|
||||||
|
strcpy(ping_packet.msg, "Hello there!\n");
|
||||||
|
|
||||||
|
ping_packet.header.checksum = htons(internet_checksum(&ping_packet, sizeof(PingPacket)));
|
||||||
|
|
||||||
|
int rc = sendto(fd, &ping_packet, sizeof(PingPacket), 0, (const struct sockaddr*)&peer_address, sizeof(sockaddr_in));
|
||||||
|
if (rc < 0) {
|
||||||
|
perror("sendto");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue