| /* |
| * 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) { |
| return; |
| } |
| |
| frag = net_pkt_get_data(ctx, K_NO_WAIT); |
| if (!frag) { |
| 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) { |
| 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); |
| } |