1 /**
2 * Copyright (c) 2025 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /*
8 * "Bottom"/Linux/Host side of the userchannel driver. This file is built in the native_simulator
9 * runner context with the host libC, but it's functionality can be called from the "embedded" side
10 */
11
12 #include <stdbool.h>
13 #include <string.h>
14 #include <errno.h>
15 #include <poll.h>
16 #include <unistd.h>
17 #include <sys/socket.h>
18 #include <limits.h>
19 #include <netinet/in.h>
20 #include <arpa/inet.h>
21 #include <nsi_errno.h>
22
23 #define BTPROTO_HCI 1
24 #define HCI_CHANNEL_USER 1
25
26 struct sockaddr_hci {
27 sa_family_t hci_family;
28 unsigned short hci_dev;
29 unsigned short hci_channel;
30 };
31
user_chan_rx_ready(int fd)32 bool user_chan_rx_ready(int fd)
33 {
34 struct pollfd pollfd = {.fd = fd, .events = POLLIN};
35
36 return (poll(&pollfd, 1, 0) == 1);
37 }
38
user_chan_is_ipaddr_ok(char ip_addr[])39 int user_chan_is_ipaddr_ok(char ip_addr[])
40 {
41 struct in_addr addr;
42
43 return inet_pton(AF_INET, ip_addr, &addr);
44 }
45
user_chan_socket_open(unsigned short bt_dev_index)46 int user_chan_socket_open(unsigned short bt_dev_index)
47 {
48 int fd;
49 struct sockaddr_hci addr;
50
51 fd = socket(PF_BLUETOOTH, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, BTPROTO_HCI);
52 if (fd < 0) {
53 return -nsi_errno_to_mid(errno);
54 }
55
56 (void)memset(&addr, 0, sizeof(addr));
57 addr.hci_family = AF_BLUETOOTH;
58 addr.hci_dev = bt_dev_index;
59 addr.hci_channel = HCI_CHANNEL_USER;
60
61 if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
62 int err = -nsi_errno_to_mid(errno);
63
64 close(fd);
65 return err;
66 }
67
68 return fd;
69 }
70
71
user_chan_net_connect(char ip_addr[],unsigned int port)72 int user_chan_net_connect(char ip_addr[], unsigned int port)
73 {
74 int fd;
75 struct sockaddr_in addr;
76
77 fd = socket(AF_INET, SOCK_STREAM, 0);
78 if (fd < 0) {
79 return -nsi_errno_to_mid(errno);
80 }
81
82 addr.sin_family = AF_INET;
83 addr.sin_port = htons(port);
84 if (inet_pton(AF_INET, ip_addr, &(addr.sin_addr)) <= 0) {
85 int err = -nsi_errno_to_mid(errno);
86
87 close(fd);
88 return err;
89 }
90
91 if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
92 int err = -nsi_errno_to_mid(errno);
93
94 close(fd);
95 return err;
96 }
97
98 return fd;
99 }
100