root/src/add-ons/kernel/network/stack/stack_interface.cpp
/*
 * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
 * Distributed under the terms of the MIT License.
 */

#include "stack_private.h"


/*!     Interface module providing networking to the kernel.
*/


static status_t
stack_interface_open(int family, int type, int protocol, net_socket** _socket)
{
        return gNetSocketModule.open_socket(family, type, protocol, _socket);
}


static status_t
stack_interface_close(net_socket* socket)
{
        return gNetSocketModule.close(socket);
}


static status_t
stack_interface_free(net_socket* socket)
{
        gNetSocketModule.free(socket);
        return B_OK;
}


static status_t
stack_interface_bind(net_socket* socket, const struct sockaddr* address,
        socklen_t addressLength)
{
        return gNetSocketModule.bind(socket, address, addressLength);
}


static status_t
stack_interface_shutdown(net_socket* socket, int how)
{
        return gNetSocketModule.shutdown(socket, how);
}


static status_t
stack_interface_connect(net_socket* socket, const struct sockaddr* address,
        socklen_t addressLength)
{
        return gNetSocketModule.connect(socket, address, addressLength);
}


static status_t
stack_interface_listen(net_socket* socket, int backlog)
{
        return gNetSocketModule.listen(socket, backlog);
}


static status_t
stack_interface_accept(net_socket* socket, struct sockaddr* address,
        socklen_t* _addressLength, net_socket** _acceptedSocket)
{
        return gNetSocketModule.accept(socket, address, _addressLength,
                _acceptedSocket);
}


static ssize_t
stack_interface_recv(net_socket* socket, void* data, size_t length, int flags)
{
        return gNetSocketModule.receive(socket, NULL, data, length, flags);
}


static ssize_t
stack_interface_recvfrom(net_socket* socket, void* data, size_t length,
        int flags, struct sockaddr* address, socklen_t* _addressLength)
{
        msghdr message;
        iovec vec = { data, length };
        message.msg_name = address;
        if (_addressLength != NULL)
                message.msg_namelen = *_addressLength;
        else
                message.msg_namelen = 0;
        message.msg_iov = &vec;
        message.msg_iovlen = 1;
        message.msg_control = NULL;
        message.msg_controllen = 0;
        message.msg_flags = 0;

        ssize_t received = gNetSocketModule.receive(socket, &message, data, length,
                flags);

        if (received >= 0 && _addressLength != NULL)
                *_addressLength = message.msg_namelen;

        return received;
}


static ssize_t
stack_interface_recvmsg(net_socket* socket, struct msghdr* message, int flags)
{
        void* buffer = NULL;
        size_t length = 0;
        if (message->msg_iovlen > 0) {
                buffer = message->msg_iov[0].iov_base;
                length = message->msg_iov[0].iov_len;
        }

        return gNetSocketModule.receive(socket, message, buffer, length, flags);
}


static ssize_t
stack_interface_send(net_socket* socket, const void* data, size_t length,
        int flags)
{
        return gNetSocketModule.send(socket, NULL, data, length, flags);
}


static ssize_t
stack_interface_sendto(net_socket* socket, const void* data, size_t length,
        int flags, const struct sockaddr* address, socklen_t addressLength)
{
        msghdr message;
        iovec vec = { (void*)data, length };
        message.msg_name = (void*)address;
        message.msg_namelen = addressLength;
        message.msg_iov = &vec;
        message.msg_iovlen = 1;
        message.msg_control = NULL;
        message.msg_controllen = 0;
        message.msg_flags = 0;

        return gNetSocketModule.send(socket, &message, data, length, flags);
}


static ssize_t
stack_interface_sendmsg(net_socket* socket, const struct msghdr* message,
        int flags)
{
        void* buffer = NULL;
        size_t length = 0;
        if (message->msg_iovlen > 0) {
                buffer = message->msg_iov[0].iov_base;
                length = message->msg_iov[0].iov_len;
        }

        return gNetSocketModule.send(socket, (msghdr*)message, buffer, length,
                flags);
}


static status_t
stack_interface_getsockopt(net_socket* socket, int level, int option,
        void* value, socklen_t* _length)
{
        int length = *_length;
        status_t error = gNetSocketModule.getsockopt(socket, level, option, value,
                &length);
        *_length = length;
        return error;
}


static status_t
stack_interface_setsockopt(net_socket* socket, int level, int option,
        const void* value, socklen_t length)
{
        return gNetSocketModule.setsockopt(socket, level, option, value, length);
}


static status_t
stack_interface_getpeername(net_socket* socket, struct sockaddr* address,
        socklen_t* _addressLength)
{
        return gNetSocketModule.getpeername(socket, address, _addressLength);
}


static status_t
stack_interface_getsockname(net_socket* socket, struct sockaddr* address,
        socklen_t* _addressLength)
{
        return gNetSocketModule.getsockname(socket, address, _addressLength);
}


static int
stack_interface_sockatmark(net_socket* socket)
{
        // TODO: sockatmark() missing
        return B_UNSUPPORTED;
}


static status_t
stack_interface_socketpair(int family, int type, int protocol,
        net_socket* _sockets[2])
{
        return gNetSocketModule.socketpair(family, type, protocol, _sockets);
}


static status_t
stack_interface_ioctl(net_socket* socket, uint32 op, void* buffer,
        size_t length)
{
        return gNetSocketModule.control(socket, op, buffer, length);
}


static status_t
stack_interface_select(net_socket* socket, uint8 event, struct selectsync* sync)
{
        return gNetSocketModule.request_notification(socket, event, sync);
}


static status_t
stack_interface_deselect(net_socket* socket, uint8 event,
        struct selectsync* sync)
{
        return gNetSocketModule.cancel_notification(socket, event, sync);
}


status_t
stack_interface_get_next_socket_stat(int family, uint32* cookie,
        struct net_stat* stat)
{
        return gNetSocketModule.get_next_stat(cookie, family, stat);
}


static status_t
stack_interface_std_ops(int32 op, ...)
{
        switch (op) {
                case B_MODULE_INIT:
                        return init_stack();
                case B_MODULE_UNINIT:
                        return uninit_stack();

                default:
                        return B_ERROR;
        }
}


net_stack_interface_module_info gNetStackInterfaceModule = {
        {
                NET_STACK_INTERFACE_MODULE_NAME,
                0,
                stack_interface_std_ops
        },

        &stack_interface_open,
        &stack_interface_close,
        &stack_interface_free,

        &stack_interface_bind,
        &stack_interface_shutdown,
        &stack_interface_connect,
        &stack_interface_listen,
        &stack_interface_accept,

        &stack_interface_recv,
        &stack_interface_recvfrom,
        &stack_interface_recvmsg,

        &stack_interface_send,
        &stack_interface_sendto,
        &stack_interface_sendmsg,

        &stack_interface_getsockopt,
        &stack_interface_setsockopt,

        &stack_interface_getpeername,
        &stack_interface_getsockname,

        &stack_interface_sockatmark,

        &stack_interface_socketpair,

        &stack_interface_ioctl,
        &stack_interface_select,
        &stack_interface_deselect,

        &stack_interface_get_next_socket_stat
};