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 <sys/un.h>
19 #include <limits.h>
20 #include <netinet/in.h>
21 #include <arpa/inet.h>
22 #include <nsi_errno.h>
23 #include <nsi_tracing.h>
24
25 #define BTPROTO_HCI 1
26 #define HCI_CHANNEL_USER 1
27
28 struct sockaddr_hci {
29 sa_family_t hci_family;
30 unsigned short hci_dev;
31 unsigned short hci_channel;
32 };
33
user_chan_rx_ready(int fd)34 bool user_chan_rx_ready(int fd)
35 {
36 struct pollfd pollfd = {.fd = fd, .events = POLLIN};
37
38 return (poll(&pollfd, 1, 0) == 1);
39 }
40
user_chan_is_ipaddr_ok(char ip_addr[])41 int user_chan_is_ipaddr_ok(char ip_addr[])
42 {
43 struct in_addr addr;
44
45 return inet_pton(AF_INET, ip_addr, &addr);
46 }
47
user_chan_socket_open(unsigned short bt_dev_index)48 int user_chan_socket_open(unsigned short bt_dev_index)
49 {
50 int fd;
51 struct sockaddr_hci addr;
52
53 fd = socket(PF_BLUETOOTH, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, BTPROTO_HCI);
54 if (fd < 0) {
55 return -nsi_errno_to_mid(errno);
56 }
57
58 (void)memset(&addr, 0, sizeof(addr));
59 addr.hci_family = AF_BLUETOOTH;
60 addr.hci_dev = bt_dev_index;
61 addr.hci_channel = HCI_CHANNEL_USER;
62
63 if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
64 int err = -nsi_errno_to_mid(errno);
65
66 close(fd);
67 return err;
68 }
69
70 return fd;
71 }
72
73
user_chan_net_connect(char ip_addr[],unsigned int port)74 int user_chan_net_connect(char ip_addr[], unsigned int port)
75 {
76 int fd;
77 struct sockaddr_in addr;
78
79 fd = socket(AF_INET, SOCK_STREAM, 0);
80 if (fd < 0) {
81 return -nsi_errno_to_mid(errno);
82 }
83
84 addr.sin_family = AF_INET;
85 addr.sin_port = htons(port);
86 if (inet_pton(AF_INET, ip_addr, &(addr.sin_addr)) <= 0) {
87 int err = -nsi_errno_to_mid(errno);
88
89 close(fd);
90 return err;
91 }
92
93 if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
94 int err = -nsi_errno_to_mid(errno);
95
96 close(fd);
97 return err;
98 }
99
100 return fd;
101 }
102
user_chan_unix_connect(char socket_path[])103 int user_chan_unix_connect(char socket_path[])
104 {
105 int fd;
106 struct sockaddr_un addr;
107 size_t socket_path_size = strlen(socket_path);
108
109 if (socket_path_size >= sizeof(addr.sun_path)) {
110 nsi_print_error_and_exit("Unix socket path too long (%zu>=%zu)\n",
111 socket_path_size, sizeof(addr.sun_path));
112 }
113
114 fd = socket(AF_UNIX, SOCK_STREAM, 0);
115 if (fd < 0) {
116 return -nsi_errno_to_mid(errno);
117 }
118
119 addr.sun_family = AF_UNIX;
120 strcpy(addr.sun_path, socket_path);
121
122 if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
123 int err = -nsi_errno_to_mid(errno);
124
125 close(fd);
126 return err;
127 }
128
129 return fd;
130 }
131