Refactor the userchan driver into a top and a bottom part. The bottom is the one which interacts with the host and is built with the host libC, while the top is built with the embedded code and whatever libC that is built with. Errors (errno) is converted between the top and bottom to ensure they are coherent with the local libC. Signed-off-by: Alberto Escolar Piedras <alberto.escolar.piedras@nordicsemi.no>
100 lines
1.9 KiB
C
100 lines
1.9 KiB
C
/**
|
|
* Copyright (c) 2025 Nordic Semiconductor ASA
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
/*
|
|
* "Bottom"/Linux/Host side of the userchannel driver. This file is built in the native_simulator
|
|
* runner context with the host libC, but it's functionality can be called from the "embedded" side
|
|
*/
|
|
|
|
#include <stdbool.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <poll.h>
|
|
#include <unistd.h>
|
|
#include <sys/socket.h>
|
|
#include <limits.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
#include <nsi_errno.h>
|
|
|
|
#define BTPROTO_HCI 1
|
|
#define HCI_CHANNEL_USER 1
|
|
|
|
struct sockaddr_hci {
|
|
sa_family_t hci_family;
|
|
unsigned short hci_dev;
|
|
unsigned short hci_channel;
|
|
};
|
|
|
|
bool user_chan_rx_ready(int fd)
|
|
{
|
|
struct pollfd pollfd = {.fd = fd, .events = POLLIN};
|
|
|
|
return (poll(&pollfd, 1, 0) == 1);
|
|
}
|
|
|
|
int user_chan_is_ipaddr_ok(char ip_addr[])
|
|
{
|
|
struct in_addr addr;
|
|
|
|
return inet_pton(AF_INET, ip_addr, &addr);
|
|
}
|
|
|
|
int user_chan_socket_open(unsigned short bt_dev_index)
|
|
{
|
|
int fd;
|
|
struct sockaddr_hci addr;
|
|
|
|
fd = socket(PF_BLUETOOTH, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, BTPROTO_HCI);
|
|
if (fd < 0) {
|
|
return -nsi_errno_to_mid(errno);
|
|
}
|
|
|
|
(void)memset(&addr, 0, sizeof(addr));
|
|
addr.hci_family = AF_BLUETOOTH;
|
|
addr.hci_dev = bt_dev_index;
|
|
addr.hci_channel = HCI_CHANNEL_USER;
|
|
|
|
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
|
int err = -nsi_errno_to_mid(errno);
|
|
|
|
close(fd);
|
|
return err;
|
|
}
|
|
|
|
return fd;
|
|
}
|
|
|
|
|
|
int user_chan_net_connect(char ip_addr[], unsigned int port)
|
|
{
|
|
int fd;
|
|
struct sockaddr_in addr;
|
|
|
|
fd = socket(AF_INET, SOCK_STREAM, 0);
|
|
if (fd < 0) {
|
|
return -nsi_errno_to_mid(errno);
|
|
}
|
|
|
|
addr.sin_family = AF_INET;
|
|
addr.sin_port = htons(port);
|
|
if (inet_pton(AF_INET, ip_addr, &(addr.sin_addr)) <= 0) {
|
|
int err = -nsi_errno_to_mid(errno);
|
|
|
|
close(fd);
|
|
return err;
|
|
}
|
|
|
|
if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
|
int err = -nsi_errno_to_mid(errno);
|
|
|
|
close(fd);
|
|
return err;
|
|
}
|
|
|
|
return fd;
|
|
}
|