1 /*
2  * Copyright (c) 2018 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/logging/log.h>
8 LOG_MODULE_REGISTER(log_backend_net, CONFIG_LOG_DEFAULT_LEVEL);
9 
10 #include <zephyr/sys/util_macro.h>
11 #include <zephyr/logging/log_backend.h>
12 #include <zephyr/logging/log_core.h>
13 #include <zephyr/logging/log_output.h>
14 #include <zephyr/logging/log_backend_net.h>
15 #include <zephyr/net/hostname.h>
16 #include <zephyr/net/net_if.h>
17 #include <zephyr/net/net_mgmt.h>
18 #include <zephyr/net/socket.h>
19 
20 /* Set this to 1 if you want to see what is being sent to server */
21 #define DEBUG_PRINTING 0
22 
23 #define DBG(fmt, ...) IF_ENABLED(DEBUG_PRINTING, (printk(fmt, ##__VA_ARGS__)))
24 
25 #if defined(CONFIG_NET_IPV6) || CONFIG_NET_HOSTNAME_ENABLE
26 #define MAX_HOSTNAME_LEN NET_IPV6_ADDR_LEN
27 #else
28 #define MAX_HOSTNAME_LEN NET_IPV4_ADDR_LEN
29 #endif
30 
31 static char dev_hostname[MAX_HOSTNAME_LEN + 1];
32 
33 static uint8_t output_buf[CONFIG_LOG_BACKEND_NET_MAX_BUF_SIZE];
34 static bool net_init_done;
35 struct sockaddr server_addr;
36 static bool panic_mode;
37 static uint32_t log_format_current = CONFIG_LOG_BACKEND_NET_OUTPUT_DEFAULT;
38 
39 static struct log_backend_net_ctx {
40 	int sock;
41 	bool is_tcp;
42 } ctx = {
43 	.sock = -1,
44 };
45 
line_out(uint8_t * data,size_t length,void * output_ctx)46 static int line_out(uint8_t *data, size_t length, void *output_ctx)
47 {
48 	struct log_backend_net_ctx *ctx = (struct log_backend_net_ctx *)output_ctx;
49 	int ret = -ENOMEM;
50 	struct msghdr msg = { 0 };
51 	struct iovec io_vector[2];
52 	int pos = 0;
53 
54 	if (ctx == NULL) {
55 		return length;
56 	}
57 
58 #if defined(CONFIG_NET_TCP)
59 	char len[sizeof("123456789")];
60 
61 	if (ctx->is_tcp) {
62 		(void)snprintk(len, sizeof(len), "%zu ", length);
63 		io_vector[pos].iov_base = (void *)len;
64 		io_vector[pos].iov_len = strlen(len);
65 		pos++;
66 	}
67 #else
68 	if (ctx->is_tcp) {
69 		return -ENOTSUP;
70 	}
71 #endif
72 
73 	io_vector[pos].iov_base = (void *)data;
74 	io_vector[pos].iov_len = length;
75 	pos++;
76 
77 	msg.msg_iov = io_vector;
78 	msg.msg_iovlen = pos;
79 
80 	ret = zsock_sendmsg(ctx->sock, &msg, ctx->is_tcp ? 0 : ZSOCK_MSG_DONTWAIT);
81 	if (ret < 0) {
82 		goto fail;
83 	}
84 
85 	DBG(data);
86 fail:
87 	return length;
88 }
89 
90 LOG_OUTPUT_DEFINE(log_output_net, line_out, output_buf, sizeof(output_buf));
91 
do_net_init(struct log_backend_net_ctx * ctx)92 static int do_net_init(struct log_backend_net_ctx *ctx)
93 {
94 	struct sockaddr *local_addr = NULL;
95 	struct sockaddr_in6 local_addr6 = {0};
96 	struct sockaddr_in local_addr4 = {0};
97 	socklen_t server_addr_len;
98 	int ret, proto = IPPROTO_UDP, type = SOCK_DGRAM;
99 
100 	if (IS_ENABLED(CONFIG_NET_IPV4) && server_addr.sa_family == AF_INET) {
101 		local_addr = (struct sockaddr *)&local_addr4;
102 		server_addr_len = sizeof(struct sockaddr_in);
103 		local_addr4.sin_family = AF_INET;
104 		local_addr4.sin_port = 0U;
105 	}
106 
107 	if (IS_ENABLED(CONFIG_NET_IPV6) && server_addr.sa_family == AF_INET6) {
108 		local_addr = (struct sockaddr *)&local_addr6;
109 		server_addr_len = sizeof(struct sockaddr_in6);
110 		local_addr6.sin6_family = AF_INET6;
111 		local_addr6.sin6_port = 0U;
112 	}
113 
114 	if (local_addr == NULL) {
115 		DBG("Server address unknown\n");
116 		return -EINVAL;
117 	}
118 
119 	if (ctx->is_tcp) {
120 		proto = IPPROTO_TCP;
121 		type = SOCK_STREAM;
122 	}
123 
124 	ret = zsock_socket(server_addr.sa_family, type, proto);
125 	if (ret < 0) {
126 		ret = -errno;
127 		DBG("Cannot get socket (%d)\n", ret);
128 		return ret;
129 	}
130 
131 	ctx->sock = ret;
132 
133 	if (IS_ENABLED(CONFIG_NET_HOSTNAME_ENABLE)) {
134 		(void)strncpy(dev_hostname, net_hostname_get(), MAX_HOSTNAME_LEN);
135 
136 	} else if (IS_ENABLED(CONFIG_NET_IPV6) &&
137 		   server_addr.sa_family == AF_INET6) {
138 		const struct in6_addr *src;
139 
140 		src = net_if_ipv6_select_src_addr(
141 			NULL, &net_sin6(&server_addr)->sin6_addr);
142 		if (src) {
143 			net_addr_ntop(AF_INET6, src, dev_hostname,
144 				      MAX_HOSTNAME_LEN);
145 
146 			net_ipaddr_copy(&local_addr6.sin6_addr, src);
147 		} else {
148 			goto unknown;
149 		}
150 
151 	} else if (IS_ENABLED(CONFIG_NET_IPV4) &&
152 		   server_addr.sa_family == AF_INET) {
153 		const struct in_addr *src;
154 
155 		src = net_if_ipv4_select_src_addr(
156 				  NULL, &net_sin(&server_addr)->sin_addr);
157 
158 		if (src) {
159 			net_addr_ntop(AF_INET, src, dev_hostname,
160 				      MAX_HOSTNAME_LEN);
161 
162 			net_ipaddr_copy(&local_addr4.sin_addr, src);
163 		} else {
164 			goto unknown;
165 		}
166 
167 	} else {
168 	unknown:
169 		DBG("Cannot setup local socket\n");
170 		ret = -EINVAL;
171 		goto err;
172 	}
173 
174 	ret = zsock_bind(ctx->sock, local_addr, server_addr_len);
175 	if (ret < 0) {
176 		ret = -errno;
177 		DBG("Cannot bind socket (%d)\n", ret);
178 		goto err;
179 	}
180 
181 	ret = zsock_connect(ctx->sock, &server_addr, server_addr_len);
182 	if (ret < 0) {
183 		ret = -errno;
184 		DBG("Cannot connect socket (%d)\n", ret);
185 		goto err;
186 	}
187 
188 	log_output_ctx_set(&log_output_net, ctx);
189 	log_output_hostname_set(&log_output_net, dev_hostname);
190 
191 	return 0;
192 
193 err:
194 	(void)zsock_close(ctx->sock);
195 	ctx->sock = -1;
196 
197 	return ret;
198 }
199 
process(const struct log_backend * const backend,union log_msg_generic * msg)200 static void process(const struct log_backend *const backend,
201 		    union log_msg_generic *msg)
202 {
203 	uint32_t flags = LOG_OUTPUT_FLAG_FORMAT_SYSLOG |
204 			 LOG_OUTPUT_FLAG_TIMESTAMP |
205 			 LOG_OUTPUT_FLAG_THREAD;
206 
207 	if (panic_mode) {
208 		return;
209 	}
210 
211 	if (!net_init_done && do_net_init(&ctx) == 0) {
212 		net_init_done = true;
213 	}
214 
215 	log_format_func_t log_output_func = log_format_func_t_get(log_format_current);
216 
217 	log_output_func(&log_output_net, &msg->log, flags);
218 }
219 
format_set(const struct log_backend * const backend,uint32_t log_type)220 static int format_set(const struct log_backend *const backend, uint32_t log_type)
221 {
222 	log_format_current = log_type;
223 	return 0;
224 }
225 
check_net_init_done(void)226 static bool check_net_init_done(void)
227 {
228 	bool ret = false;
229 
230 	if (net_init_done) {
231 		/* Release context so it can be recreated with the specified ip address
232 		 * next time process() is called
233 		 */
234 		struct log_backend_net_ctx *ctx = log_output_net.control_block->ctx;
235 		int released;
236 
237 		released = zsock_close(ctx->sock);
238 		if (released < 0) {
239 			LOG_ERR("Cannot release socket (%d)", ret);
240 			ret = false;
241 		} else {
242 			/* The socket is successfully closed so we flag it
243 			 * to be recreated with the new ip address
244 			 */
245 			net_init_done = false;
246 			ret = true;
247 		}
248 
249 		ctx->sock = -1;
250 
251 		return ret;
252 	}
253 
254 	return true;
255 }
256 
log_backend_net_set_addr(const char * addr)257 bool log_backend_net_set_addr(const char *addr)
258 {
259 	bool ret = check_net_init_done();
260 
261 	if (!ret) {
262 		return ret;
263 	}
264 
265 	net_sin(&server_addr)->sin_port = htons(514);
266 
267 	ret = net_ipaddr_parse(addr, strlen(addr), &server_addr);
268 	if (!ret) {
269 		LOG_ERR("Cannot parse syslog server address");
270 		return ret;
271 	}
272 
273 	return ret;
274 }
275 
log_backend_net_set_ip(const struct sockaddr * addr)276 bool log_backend_net_set_ip(const struct sockaddr *addr)
277 {
278 	bool ret = check_net_init_done();
279 
280 	if (!ret) {
281 		return ret;
282 	}
283 
284 	if ((IS_ENABLED(CONFIG_NET_IPV4) && addr->sa_family == AF_INET) ||
285 	    (IS_ENABLED(CONFIG_NET_IPV6) && addr->sa_family == AF_INET6)) {
286 		memcpy(&server_addr, addr, sizeof(server_addr));
287 
288 		net_port_set_default(&server_addr, 514);
289 	} else {
290 		LOG_ERR("Unknown address family");
291 		return false;
292 	}
293 
294 	return ret;
295 }
296 
297 #if defined(CONFIG_NET_HOSTNAME_ENABLE)
log_backend_net_hostname_set(char * hostname,size_t len)298 void log_backend_net_hostname_set(char *hostname, size_t len)
299 {
300 	(void)strncpy(dev_hostname, hostname, MIN(len, MAX_HOSTNAME_LEN));
301 	log_output_hostname_set(&log_output_net, dev_hostname);
302 }
303 #endif
304 
log_backend_net_start(void)305 void log_backend_net_start(void)
306 {
307 	const struct log_backend *backend = log_backend_net_get();
308 
309 	if (!log_backend_is_active(backend)) {
310 		log_backend_activate(backend, backend->cb->ctx);
311 	}
312 }
313 
init_net(struct log_backend const * const backend)314 static void init_net(struct log_backend const *const backend)
315 {
316 	ARG_UNUSED(backend);
317 
318 	if (sizeof(CONFIG_LOG_BACKEND_NET_SERVER) != 1) {
319 		/* Non empty address, set server via Kconfig defaults */
320 		const char *server = CONFIG_LOG_BACKEND_NET_SERVER;
321 		bool ret;
322 
323 		if (memcmp(server, "tcp://", sizeof("tcp://") - 1) == 0) {
324 			server += sizeof("tcp://") - 1;
325 			ctx.is_tcp = true;
326 		}
327 
328 		ret = log_backend_net_set_addr(server);
329 		if (!ret) {
330 			return;
331 		}
332 	}
333 
334 	log_backend_deactivate(log_backend_net_get());
335 }
336 
panic(struct log_backend const * const backend)337 static void panic(struct log_backend const *const backend)
338 {
339 	panic_mode = true;
340 }
341 
342 /* After initialization of the logger, this function avoids
343  * the logger subsys to enable it.
344  */
backend_ready(const struct log_backend * const backend)345 static int backend_ready(const struct log_backend *const backend)
346 {
347 	return log_backend_is_active(backend) ? 0 : -EAGAIN;
348 }
349 
350 const struct log_backend_api log_backend_net_api = {
351 	.panic = panic,
352 	.init = init_net,
353 	.is_ready = backend_ready,
354 	.process = process,
355 	.format_set = format_set,
356 };
357 
358 /* Note that the backend can be activated only after we have networking
359  * subsystem ready so we must not start it immediately.
360  */
361 LOG_BACKEND_DEFINE(log_backend_net, log_backend_net_api,
362 		   IS_ENABLED(CONFIG_LOG_BACKEND_NET_AUTOSTART));
363 
log_backend_net_get(void)364 const struct log_backend *log_backend_net_get(void)
365 {
366 	return &log_backend_net;
367 }
368 
369 #if defined(CONFIG_LOG_BACKEND_NET_USE_CONNECTION_MANAGER)
l4_event_handler(uint64_t mgmt_event,struct net_if * iface,void * info,size_t info_length,void * user_data)370 static void l4_event_handler(uint64_t mgmt_event, struct net_if *iface, void *info,
371 			     size_t info_length, void *user_data)
372 {
373 	ARG_UNUSED(iface);
374 	ARG_UNUSED(info);
375 	ARG_UNUSED(info_length);
376 	ARG_UNUSED(user_data);
377 
378 	if (mgmt_event == NET_EVENT_L4_CONNECTED) {
379 		log_backend_net_start();
380 	} else if (mgmt_event == NET_EVENT_L4_DISCONNECTED) {
381 		log_backend_deactivate(log_backend_net_get());
382 	}
383 }
384 
385 NET_MGMT_REGISTER_EVENT_HANDLER(log_backend_net_event_handler,
386 				NET_EVENT_L4_CONNECTED | NET_EVENT_L4_DISCONNECTED,
387 				&l4_event_handler, NULL);
388 #endif /* CONFIG_LOG_BACKEND_NET_USE_CONNECTION_MANAGER */
389