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