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