232 lines
5.2 KiB
C
232 lines
5.2 KiB
C
/*
|
|
* Copyright (c) 2018 Intel Corporation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <logging/sys_log.h>
|
|
|
|
#include <net/net_pkt.h>
|
|
#include <net/net_context.h>
|
|
|
|
/* Set this to 1 if you want to see what is being sent to server */
|
|
#define DEBUG_PRINTING 0
|
|
|
|
static struct net_context *ctx;
|
|
static struct sockaddr server_addr;
|
|
|
|
/* FIXME: As there is no way to figure out these values in the hook
|
|
* function, use some pre-defined values. Change this to use the
|
|
* real facility and severity of the logging call when that info is
|
|
* available.
|
|
*/
|
|
static const int facility = 16; /* local0 */
|
|
static const int severity = 6; /* info */
|
|
|
|
#define DATE_EPOCH "1970-01-01T00:00:00.000000-00:00"
|
|
static char date[sizeof(DATE_EPOCH)];
|
|
|
|
#if defined(CONFIG_NET_IPV6) || CONFIG_NET_HOSTNAME_ENABLE
|
|
#define MAX_HOSTNAME_LEN NET_IPV6_ADDR_LEN
|
|
#else
|
|
#define MAX_HOSTNAME_LEN NET_IPV4_ADDR_LEN
|
|
#endif
|
|
|
|
static char hostname[MAX_HOSTNAME_LEN + 1];
|
|
|
|
NET_PKT_SLAB_DEFINE(syslog_tx_pkts, CONFIG_SYS_LOG_BACKEND_NET_MAX_BUF);
|
|
NET_BUF_POOL_DEFINE(syslog_tx_bufs, CONFIG_SYS_LOG_BACKEND_NET_MAX_BUF,
|
|
CONFIG_SYS_LOG_BACKEND_NET_MAX_BUF_SIZE,
|
|
CONFIG_NET_BUF_USER_DATA_SIZE, NULL);
|
|
|
|
static struct k_mem_slab *get_tx_slab(void)
|
|
{
|
|
return &syslog_tx_pkts;
|
|
}
|
|
|
|
struct net_buf_pool *get_data_pool(void)
|
|
{
|
|
return &syslog_tx_bufs;
|
|
}
|
|
|
|
static void fill_header(struct net_buf *buf)
|
|
{
|
|
snprintk(net_buf_tail(buf),
|
|
net_buf_tailroom(buf),
|
|
"<%d>1 %s %s - - - - ",
|
|
facility * 8 + severity,
|
|
date,
|
|
hostname);
|
|
|
|
net_buf_add(buf, strlen(buf->data));
|
|
}
|
|
|
|
static void syslog_hook_net(const char *fmt, ...)
|
|
{
|
|
struct net_pkt *pkt;
|
|
struct net_buf *frag;
|
|
u8_t *ptr;
|
|
va_list vargs;
|
|
int ret;
|
|
|
|
pkt = net_pkt_get_tx(ctx, K_NO_WAIT);
|
|
if (pkt == NULL) {
|
|
return;
|
|
}
|
|
|
|
frag = net_pkt_get_data(ctx, K_NO_WAIT);
|
|
if (frag == NULL) {
|
|
net_pkt_unref(pkt);
|
|
return;
|
|
}
|
|
|
|
net_pkt_frag_add(pkt, frag);
|
|
|
|
fill_header(frag);
|
|
|
|
va_start(vargs, fmt);
|
|
|
|
ptr = net_buf_tail(frag);
|
|
|
|
ret = vsnprintk(ptr, (net_buf_tailroom(frag) - 1), fmt, vargs);
|
|
if (ret < 0) {
|
|
net_pkt_unref(pkt);
|
|
return;
|
|
}
|
|
|
|
va_end(vargs);
|
|
|
|
if (ret > 0 && ptr[ret - 1] == '\n') {
|
|
/* No need to send \n to peer so strip it away */
|
|
ret--;
|
|
}
|
|
|
|
net_buf_add(frag, ret);
|
|
|
|
#if DEBUG_PRINTING
|
|
{
|
|
static u32_t count;
|
|
|
|
printk("%d:%s", ++count, frag->data);
|
|
}
|
|
#endif
|
|
ret = net_context_send(pkt, NULL, K_NO_WAIT, NULL, NULL);
|
|
if (ret < 0) {
|
|
net_pkt_unref(pkt);
|
|
}
|
|
}
|
|
|
|
void syslog_net_hook_install(void)
|
|
{
|
|
#if defined(CONFIG_NET_IPV6)
|
|
struct sockaddr_in6 local_addr6 = {
|
|
.sin6_family = AF_INET6,
|
|
.sin6_port = 0,
|
|
};
|
|
#endif
|
|
#if defined(CONFIG_NET_IPV4)
|
|
struct sockaddr_in local_addr4 = {
|
|
.sin_family = AF_INET,
|
|
.sin_port = 0,
|
|
};
|
|
#endif
|
|
struct sockaddr *local_addr = NULL;
|
|
socklen_t local_addr_len = 0;
|
|
socklen_t server_addr_len = 0;
|
|
int ret;
|
|
|
|
net_sin(&server_addr)->sin_port = htons(514);
|
|
|
|
ret = net_ipaddr_parse(CONFIG_SYS_LOG_BACKEND_NET_SERVER,
|
|
sizeof(CONFIG_SYS_LOG_BACKEND_NET_SERVER) - 1,
|
|
&server_addr);
|
|
if (ret == 0) {
|
|
SYS_LOG_ERR("Cannot configure syslog server address");
|
|
return;
|
|
}
|
|
|
|
#if defined(CONFIG_NET_IPV4)
|
|
if (server_addr.sa_family == AF_INET) {
|
|
local_addr = (struct sockaddr *)&local_addr4;
|
|
local_addr_len = sizeof(struct sockaddr_in);
|
|
server_addr_len = sizeof(struct sockaddr_in);
|
|
}
|
|
#endif
|
|
|
|
#if defined(CONFIG_NET_IPV6)
|
|
if (server_addr.sa_family == AF_INET6) {
|
|
local_addr = (struct sockaddr *)&local_addr6;
|
|
local_addr_len = sizeof(struct sockaddr_in6);
|
|
server_addr_len = sizeof(struct sockaddr_in6);
|
|
}
|
|
#endif
|
|
|
|
ret = net_context_get(server_addr.sa_family, SOCK_DGRAM, IPPROTO_UDP,
|
|
&ctx);
|
|
if (ret < 0) {
|
|
SYS_LOG_ERR("Cannot get context (%d)", ret);
|
|
return;
|
|
}
|
|
|
|
#if CONFIG_NET_HOSTNAME_ENABLE
|
|
(void)memcpy(hostname, net_hostname_get(), MAX_HOSTNAME_LEN);
|
|
#else /* CONFIG_NET_HOSTNAME_ENABLE */
|
|
if (server_addr.sa_family == AF_INET6) {
|
|
#if defined(CONFIG_NET_IPV6)
|
|
const struct in6_addr *src;
|
|
|
|
src = net_if_ipv6_select_src_addr(
|
|
NULL, &net_sin6(&server_addr)->sin6_addr);
|
|
if (src) {
|
|
net_addr_ntop(AF_INET6, src, hostname,
|
|
MAX_HOSTNAME_LEN);
|
|
|
|
net_ipaddr_copy(&local_addr6.sin6_addr, src);
|
|
} else {
|
|
goto unknown;
|
|
}
|
|
#else
|
|
goto unknown;
|
|
#endif
|
|
} else if (server_addr.sa_family == AF_INET) {
|
|
#if defined(CONFIG_NET_IPV4)
|
|
struct net_if_ipv4 *ipv4;
|
|
struct net_if *iface;
|
|
|
|
iface = net_if_ipv4_select_src_iface(
|
|
&net_sin(&server_addr)->sin_addr);
|
|
ipv4 = iface->config.ip.ipv4;
|
|
|
|
net_ipaddr_copy(&local_addr4.sin_addr,
|
|
&ipv4->unicast[0].address.in_addr);
|
|
|
|
net_addr_ntop(AF_INET, &local_addr4.sin_addr, hostname,
|
|
MAX_HOSTNAME_LEN);
|
|
#else
|
|
goto unknown;
|
|
#endif
|
|
} else {
|
|
unknown:
|
|
strncpy(hostname, "zephyr", MAX_HOSTNAME_LEN);
|
|
}
|
|
#endif /* CONFIG_NET_HOSTNAME_ENABLE */
|
|
|
|
ret = net_context_bind(ctx, local_addr, local_addr_len);
|
|
if (ret < 0) {
|
|
SYS_LOG_ERR("Cannot bind context (%d)", ret);
|
|
return;
|
|
}
|
|
|
|
ret = net_context_connect(ctx, &server_addr, server_addr_len,
|
|
NULL, K_NO_WAIT, NULL);
|
|
|
|
/* We do not care about return value for this UDP connect call that
|
|
* basically does nothing. Calling the connect is only useful so that
|
|
* we can see the syslog connection in net-shell.
|
|
*/
|
|
|
|
net_context_setup_pools(ctx, get_tx_slab, get_data_pool);
|
|
|
|
syslog_hook_install(syslog_hook_net);
|
|
}
|