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