1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Log to syslog.
4  *
5  * Copyright (c) 2020, Heinrich Schuchardt <xypron.glpk@gmx.de>
6  */
7 
8 #include <common.h>
9 #include <log.h>
10 #include <net.h>
11 #include <asm/global_data.h>
12 
13 DECLARE_GLOBAL_DATA_PTR;
14 
15 #define BUFFER_SIZE 480
16 
append(char ** buf,char * buf_end,const char * fmt,...)17 static void append(char **buf, char *buf_end, const char *fmt, ...)
18 {
19 	va_list args;
20 	size_t size = buf_end - *buf;
21 
22 	va_start(args, fmt);
23 	vsnprintf(*buf, size, fmt, args);
24 	va_end(args);
25 	*buf += strlen(*buf);
26 }
27 
log_syslog_emit(struct log_device * ldev,struct log_rec * rec)28 static int log_syslog_emit(struct log_device *ldev, struct log_rec *rec)
29 {
30 	int ret;
31 	int fmt = gd->log_fmt;
32 	char msg[BUFFER_SIZE];
33 	char *msg_end = msg + BUFFER_SIZE;
34 	char *ptr = msg;
35 	char *iphdr;
36 	char *log_msg;
37 	int eth_hdr_size;
38 	struct in_addr bcast_ip;
39 	unsigned int log_level;
40 	char *log_hostname;
41 
42 	/* Setup packet buffers */
43 	ret = net_init();
44 	if (ret)
45 		return ret;
46 	/* Disable hardware and put it into the reset state */
47 	eth_halt();
48 	/* Set current device according to environment variables */
49 	eth_set_current();
50 	/* Get hardware ready for send and receive operations */
51 	ret = eth_init();
52 	if (ret < 0) {
53 		eth_halt();
54 		goto out;
55 	}
56 
57 	memset(msg, 0, BUFFER_SIZE);
58 
59 	/* Set ethernet header */
60 	eth_hdr_size = net_set_ether((uchar *)ptr, net_bcast_ethaddr, PROT_IP);
61 	ptr += eth_hdr_size;
62 	iphdr = ptr;
63 	ptr += IP_UDP_HDR_SIZE;
64 	log_msg = ptr;
65 
66 	/*
67 	 * The syslog log levels defined in RFC 5424 match the U-Boot ones up to
68 	 * level 7 (debug).
69 	 */
70 	log_level = rec->level;
71 	if (log_level > 7)
72 		log_level = 7;
73 	/* Leave high bits as 0 to write a 'kernel message' */
74 
75 	/* Write log message to buffer */
76 	append(&ptr, msg_end, "<%u>", log_level);
77 	log_hostname = env_get("log_hostname");
78 	if (log_hostname)
79 		append(&ptr, msg_end, "%s ", log_hostname);
80 	append(&ptr, msg_end, "uboot: ");
81 	if (fmt & BIT(LOGF_LEVEL))
82 		append(&ptr, msg_end, "%s.",
83 		       log_get_level_name(rec->level));
84 	if (fmt & BIT(LOGF_CAT))
85 		append(&ptr, msg_end, "%s,",
86 		       log_get_cat_name(rec->cat));
87 	if (fmt & BIT(LOGF_FILE))
88 		append(&ptr, msg_end, "%s:", rec->file);
89 	if (fmt & BIT(LOGF_LINE))
90 		append(&ptr, msg_end, "%d-", rec->line);
91 	if (fmt & BIT(LOGF_FUNC))
92 		append(&ptr, msg_end, "%s()", rec->func);
93 	if (fmt & BIT(LOGF_MSG))
94 		append(&ptr, msg_end, "%s%s",
95 		       fmt != BIT(LOGF_MSG) ? " " : "", rec->msg);
96 	/* Consider trailing 0x00 */
97 	ptr++;
98 
99 	debug("log message: '%s'\n", log_msg);
100 
101 	/* Broadcast message */
102 	bcast_ip.s_addr = 0xFFFFFFFFL;
103 	net_set_udp_header((uchar *)iphdr, bcast_ip, 514, 514, ptr - log_msg);
104 	net_send_packet((uchar *)msg, ptr - msg);
105 
106 out:
107 	return ret;
108 }
109 
110 LOG_DRIVER(syslog) = {
111 	.name	= "syslog",
112 	.emit	= log_syslog_emit,
113 };
114