1 /*
2  * Copyright (c) 2022 René Beckmann
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /** @file mqtt_sn_transport_udp.c
8  *
9  * @brief MQTT-SN UDP transport.
10  */
11 
12 #include <errno.h>
13 
14 #include <zephyr/net/mqtt_sn.h>
15 #include <zephyr/net/net_ip.h>
16 #include <zephyr/net/socket.h>
17 #include <zephyr/net/igmp.h>
18 
19 #include <zephyr/posix/fcntl.h>
20 
21 #include <zephyr/logging/log.h>
22 LOG_MODULE_DECLARE(net_mqtt_sn, CONFIG_MQTT_SN_LOG_LEVEL);
23 
get_ip_str(const struct sockaddr * sa,char * s,size_t maxlen)24 static char *get_ip_str(const struct sockaddr *sa, char *s, size_t maxlen)
25 {
26 	switch (sa->sa_family) {
27 	case AF_INET:
28 		inet_ntop(AF_INET, &(((struct sockaddr_in *)sa)->sin_addr), s, maxlen);
29 		break;
30 
31 	case AF_INET6:
32 		inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)sa)->sin6_addr), s, maxlen);
33 		break;
34 
35 	default:
36 		strncpy(s, "Unknown AF", maxlen);
37 		break;
38 	}
39 
40 	return s;
41 }
42 
tp_udp_init(struct mqtt_sn_transport * transport)43 static int tp_udp_init(struct mqtt_sn_transport *transport)
44 {
45 	struct mqtt_sn_transport_udp *udp = UDP_TRANSPORT(transport);
46 	int err;
47 	struct sockaddr addrm;
48 	struct ip_mreqn mreqn;
49 	int optval;
50 	struct net_if *iface;
51 
52 	udp->sock = zsock_socket(udp->bcaddr.sa_family, SOCK_DGRAM, 0);
53 	if (udp->sock < 0) {
54 		return errno;
55 	}
56 
57 	LOG_DBG("Socket %d", udp->sock);
58 
59 	optval = 1;
60 	err = zsock_setsockopt(udp->sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
61 	if (err < 0) {
62 		return errno;
63 	}
64 
65 	if (IS_ENABLED(CONFIG_MQTT_SN_LOG_LEVEL_DBG)) {
66 		char ip[30], *out;
67 		uint16_t port;
68 
69 		out = get_ip_str((struct sockaddr *)&udp->bcaddr, ip, sizeof(ip));
70 		switch (udp->bcaddr.sa_family) {
71 		case AF_INET:
72 			port = ntohs(((struct sockaddr_in *)&udp->bcaddr)->sin_port);
73 			break;
74 		case AF_INET6:
75 			port = ntohs(((struct sockaddr_in6 *)&udp->bcaddr)->sin6_port);
76 			break;
77 		default:
78 			break;
79 		}
80 
81 		if (out != NULL) {
82 			LOG_DBG("Binding to Brodcast IP %s:%u", out, port);
83 		}
84 	}
85 
86 	switch (udp->bcaddr.sa_family) {
87 	case AF_INET:
88 		if (IS_ENABLED(CONFIG_NET_IPV4)) {
89 			addrm.sa_family = AF_INET;
90 			((struct sockaddr_in *)&addrm)->sin_port =
91 				((struct sockaddr_in *)&udp->bcaddr)->sin_port;
92 			((struct sockaddr_in *)&addrm)->sin_addr.s_addr = INADDR_ANY;
93 		}
94 		break;
95 	case AF_INET6:
96 		if (IS_ENABLED(CONFIG_NET_IPV6)) {
97 			addrm.sa_family = AF_INET6;
98 			((struct sockaddr_in6 *)&addrm)->sin6_port =
99 				((struct sockaddr_in6 *)&udp->bcaddr)->sin6_port;
100 			memcpy(&((struct sockaddr_in6 *)&addrm)->sin6_addr, &in6addr_any,
101 			       sizeof(struct in6_addr));
102 			break;
103 		}
104 	default:
105 		LOG_ERR("Unknown AF");
106 		return -EINVAL;
107 	}
108 
109 	err = zsock_bind(udp->sock, &addrm, sizeof(addrm));
110 	if (err) {
111 		LOG_ERR("Error during bind: %d", errno);
112 		return errno;
113 	}
114 
115 	memcpy(&mreqn.imr_multiaddr, &udp->bcaddr.data[2], sizeof(udp->bcaddr.data) - 2);
116 	if (udp->bcaddr.sa_family == AF_INET && IS_ENABLED(CONFIG_NET_IPV4)) {
117 		iface = net_if_ipv4_select_src_iface(
118 			&((struct sockaddr_in *)&udp->bcaddr)->sin_addr);
119 	} else if (udp->bcaddr.sa_family == AF_INET6 && IS_ENABLED(CONFIG_NET_IPV6)) {
120 		iface = net_if_ipv6_select_src_iface(&((struct sockaddr_in6 *)&addrm)->sin6_addr);
121 	} else {
122 		LOG_ERR("Unknown AF");
123 		return -EINVAL;
124 	}
125 	mreqn.imr_ifindex = net_if_get_by_iface(iface);
126 
127 	err = zsock_setsockopt(udp->sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreqn, sizeof(mreqn));
128 	if (err < 0) {
129 		return errno;
130 	}
131 
132 	optval = CONFIG_MQTT_SN_LIB_BROADCAST_RADIUS;
133 	err = zsock_setsockopt(udp->sock, IPPROTO_IP, IP_MULTICAST_TTL, &optval, sizeof(optval));
134 	if (err < 0) {
135 		return errno;
136 	}
137 
138 	return 0;
139 }
140 
tp_udp_deinit(struct mqtt_sn_transport * transport)141 static void tp_udp_deinit(struct mqtt_sn_transport *transport)
142 {
143 	struct mqtt_sn_transport_udp *udp = UDP_TRANSPORT(transport);
144 
145 	zsock_close(udp->sock);
146 }
147 
tp_udp_sendto(struct mqtt_sn_client * client,void * buf,size_t sz,const void * dest_addr,size_t addrlen)148 static int tp_udp_sendto(struct mqtt_sn_client *client, void *buf, size_t sz, const void *dest_addr,
149 			 size_t addrlen)
150 {
151 	struct mqtt_sn_transport_udp *udp = UDP_TRANSPORT(client->transport);
152 	int rc;
153 	int ttl;
154 	socklen_t ttl_len;
155 
156 	if (dest_addr == NULL) {
157 		LOG_HEXDUMP_DBG(buf, sz, "Sending Broadcast UDP packet");
158 
159 		/* Set ttl if requested value does not match existing*/
160 		rc = zsock_getsockopt(udp->sock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, &ttl_len);
161 		if (rc < 0) {
162 			return -errno;
163 		}
164 		if (ttl != addrlen) {
165 			ttl = addrlen;
166 			rc = zsock_setsockopt(udp->sock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl,
167 					      sizeof(ttl));
168 			if (rc < 0) {
169 				return -errno;
170 			}
171 		}
172 
173 		rc = zsock_sendto(udp->sock, buf, sz, 0, &udp->bcaddr, udp->bcaddrlen);
174 	} else {
175 		LOG_HEXDUMP_DBG(buf, sz, "Sending Addressed UDP packet");
176 		rc = zsock_sendto(udp->sock, buf, sz, 0, dest_addr, addrlen);
177 	}
178 
179 	if (rc < 0) {
180 		return -errno;
181 	}
182 
183 	if (rc != sz) {
184 		return -EIO;
185 	}
186 
187 	return 0;
188 }
189 
tp_udp_recvfrom(struct mqtt_sn_client * client,void * buffer,size_t length,void * src_addr,size_t * addrlen)190 static ssize_t tp_udp_recvfrom(struct mqtt_sn_client *client, void *buffer, size_t length,
191 			       void *src_addr, size_t *addrlen)
192 {
193 	struct mqtt_sn_transport_udp *udp = UDP_TRANSPORT(client->transport);
194 	int rc;
195 	struct sockaddr *srcaddr = src_addr;
196 
197 	rc = zsock_recvfrom(udp->sock, buffer, length, 0, src_addr, addrlen);
198 	LOG_DBG("recv %d", rc);
199 	if (rc < 0) {
200 		return -errno;
201 	}
202 
203 	LOG_HEXDUMP_DBG(buffer, rc, "recv");
204 
205 	if (*addrlen != udp->bcaddrlen) {
206 		return rc;
207 	}
208 
209 	if (memcmp(srcaddr->data, udp->bcaddr.data, *addrlen) != 0) {
210 		return rc;
211 	}
212 
213 	src_addr = NULL;
214 	*addrlen = 1;
215 	return rc;
216 }
217 
tp_udp_poll(struct mqtt_sn_client * client)218 static int tp_udp_poll(struct mqtt_sn_client *client)
219 {
220 	struct mqtt_sn_transport_udp *udp = UDP_TRANSPORT(client->transport);
221 	int rc;
222 
223 	struct zsock_pollfd pollfd = {
224 		.fd = udp->sock,
225 		.events = ZSOCK_POLLIN,
226 	};
227 
228 	rc = zsock_poll(&pollfd, 1, 0);
229 	if (rc < 1) {
230 		return rc;
231 	}
232 
233 	LOG_DBG("revents %d", pollfd.revents & ZSOCK_POLLIN);
234 
235 	return pollfd.revents & ZSOCK_POLLIN;
236 }
237 
mqtt_sn_transport_udp_init(struct mqtt_sn_transport_udp * udp,struct sockaddr * bcaddr,socklen_t addrlen)238 int mqtt_sn_transport_udp_init(struct mqtt_sn_transport_udp *udp, struct sockaddr *bcaddr,
239 			       socklen_t addrlen)
240 {
241 	if (!udp || !bcaddr || !addrlen) {
242 		return -EINVAL;
243 	}
244 
245 	memset(udp, 0, sizeof(*udp));
246 
247 	udp->tp = (struct mqtt_sn_transport){.init = tp_udp_init,
248 					     .deinit = tp_udp_deinit,
249 					     .sendto = tp_udp_sendto,
250 					     .poll = tp_udp_poll,
251 					     .recvfrom = tp_udp_recvfrom};
252 
253 	udp->sock = 0;
254 
255 	memcpy(&udp->bcaddr, bcaddr, addrlen);
256 	udp->bcaddrlen = addrlen;
257 
258 	return 0;
259 }
260