Merge "Merge net branch into master"

This commit is contained in:
Anas Nashif 2017-03-25 11:25:33 +00:00
commit 8ec959a041
53 changed files with 3592 additions and 410 deletions

View file

@ -46,7 +46,7 @@ endif
config BLUETOOTH_MONITOR_ON_DEV_NAME
default UART_QMSI_1_NAME if BLUETOOTH_DEBUG_MONITOR
if IEEE802154_CC2520_LEGACY || IEEE802154_CC2520 || IEEE802154_CC2520_RAW
if IEEE802154_CC2520
config SPI
def_bool y
@ -85,6 +85,6 @@ config IEEE802154_CC2520_GPIO_1_NAME
default GPIO_QMSI_1_NAME
endif
endif # IEEE802154_CC2520_LEGACY || IEEE802154_CC2520 || IEEE802154_CC2520_RAW
endif # IEEE802154_CC2520
endif # BOARD_QUARK_SE_C1000_DEVBOARD

View file

@ -10,9 +10,7 @@
#include <device.h>
#include <init.h>
#if defined(CONFIG_IEEE802154_CC2520_LEGACY) || \
defined(CONFIG_IEEE802154_CC2520) || \
defined(CONFIG_IEEE802154_CC2520_RAW)
#if defined(CONFIG_IEEE802154_CC2520)
#include <ieee802154/cc2520.h>
#include <gpio.h>
@ -61,6 +59,4 @@ struct cc2520_gpio_configuration *cc2520_configure_gpios(void)
return cc2520_gpios;
}
#endif /* CONFIG_IEEE802154_CC2520_LEGACY || CONFIG_IEEE802154_CC2520 ||
* CONFIG_IEEE802154_CC2520_RAW
*/
#endif /* CONFIG_IEEE802154_CC2520 */

View file

@ -21,9 +21,7 @@
#define LED0_GPIO_PORT CONFIG_GPIO_QMSI_0_NAME
#define LED0_GPIO_PIN 25
#if defined(CONFIG_IEEE802154_CC2520_LEGACY) || \
defined(CONFIG_IEEE802154_CC2520) || \
defined(CONFIG_IEEE802154_CC2520_RAW)
#if defined(CONFIG_IEEE802154_CC2520)
/* GPIO numbers where the TI cc2520 chip is connected to */
#define CC2520_GPIO_VREG_EN 0 /* PIN ?, ATP_AON_INT0 (out) */
@ -33,9 +31,7 @@
#define CC2520_GPIO_CCA 6 /* PIN 6, GPIO6 (in) */
#define CC2520_GPIO_SFD 29 /* PIN 33, GPIO29 (in) */
#endif /* CONFIG_IEEE802154_CC2520_LEGACY || CONFIG_IEEE802154_CC2520 ||
* CONFIG_IEEE802154_CC2520_RAW
*/
#endif /* CONFIG_IEEE802154_CC2520 */
#if defined(CONFIG_USB)
/* GPIO driver name */

View file

@ -7,17 +7,7 @@ menuconfig IEEE802154_CC2520
select NET_L2_IEEE802154
default n
menuconfig IEEE802154_CC2520_RAW
bool "TI CC2520 Driver RAW channel"
select NET_L2_RAW_CHANNEL
default n
help
Enable IEEE802154_CC2520 driver with RAW channel
The CC2520 driver with RAW channel allows to export radio interface
over USB making an USB 802.15.4 dongle.
if IEEE802154_CC2520 || IEEE802154_CC2520_RAW
if IEEE802154_CC2520
config IEEE802154_CC2520_DRV_NAME
string "TI CC2520 Driver's name"
@ -99,6 +89,17 @@ config IEEE802154_CC2520_MAC7
range 0 ff
help
This is the byte 7 of the MAC address.
endif
endif
endif # ! IEEE802154_CC2520_RANDOM_MAC
config IEEE802154_CC2520_RAW
bool "TI CC2520 Driver RAW channel"
select NET_L2_RAW_CHANNEL
default n
help
Enable IEEE802154_CC2520 driver with RAW channel
The CC2520 driver with RAW channel allows to export radio interface
over USB making an USB 802.15.4 dongle.
endif # IEEE802154_CC2520

View file

@ -1,5 +1,4 @@
obj-$(CONFIG_IEEE802154_CC2520) += ieee802154_cc2520.o
obj-$(CONFIG_IEEE802154_CC2520_RAW) += ieee802154_cc2520.o
obj-$(CONFIG_IEEE802154_UPIPE) += ieee802154_uart_pipe.o
obj-$(CONFIG_IEEE802154_MCR20A) += ieee802154_mcr20a.o
obj-$(CONFIG_IEEE802154_MCR20A_RAW) += ieee802154_mcr20a.o

307
include/net/dns_resolve.h Normal file
View file

@ -0,0 +1,307 @@
/** @file
* @brief DNS resolving library
*
* An API for applications to resolve a DNS name.
*/
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _DNS_RESOLVE_H
#define _DNS_RESOLVE_H
#if defined(CONFIG_DNS_RESOLVER)
#include <net/net_ip.h>
#include <net/net_context.h>
/**
* DNS query type enum
*/
enum dns_query_type {
DNS_QUERY_TYPE_A = 1, /* IPv4 */
DNS_QUERY_TYPE_AAAA = 28 /* IPv6 */
};
#ifndef DNS_MAX_NAME_SIZE
#define DNS_MAX_NAME_SIZE 20
#endif
/**
* Address info struct is passed to callback that gets all the results.
*/
struct dns_addrinfo {
struct sockaddr ai_addr;
char ai_canonname[DNS_MAX_NAME_SIZE + 1];
socklen_t ai_addrlen;
uint16_t ai_flags;
uint8_t ai_family;
uint8_t ai_socktype;
uint8_t ai_protocol;
};
/**
* Status values for the callback.
*/
enum dns_resolve_status {
DNS_EAI_BADFLAGS = -1, /* Invalid value for `ai_flags' field */
DNS_EAI_NONAME = -2, /* NAME or SERVICE is unknown */
DNS_EAI_AGAIN = -3, /* Temporary failure in name resolution */
DNS_EAI_FAIL = -4, /* Non-recoverable failure in name res */
DNS_EAI_NODATA = -5, /* No address associated with NAME */
DNS_EAI_FAMILY = -6, /* `ai_family' not supported */
DNS_EAI_SOCKTYPE = -7, /* `ai_socktype' not supported */
DNS_EAI_SERVICE = -8, /* SRV not supported for `ai_socktype' */
DNS_EAI_ADDRFAMILY = -9, /* Address family for NAME not supported */
DNS_EAI_MEMORY = -10, /* Memory allocation failure */
DNS_EAI_SYSTEM = -11, /* System error returned in `errno' */
DNS_EAI_OVERFLOW = -12, /* Argument buffer overflow */
DNS_EAI_INPROGRESS = -100, /* Processing request in progress */
DNS_EAI_CANCELED = -101, /* Request canceled */
DNS_EAI_NOTCANCELED = -102, /* Request not canceled */
DNS_EAI_ALLDONE = -103, /* All requests done */
DNS_EAI_IDN_ENCODE = -105, /* IDN encoding failed */
};
/**
* @typedef dns_resolve_cb_t
* @brief DNS resolve callback
*
* @details The DNS resolve callback is called after a successful
* DNS resolving. The resolver can call this callback multiple times, one
* for each resolved address.
*
* @param status The status of the query:
* DNS_EAI_INPROGRESS returned for each resolved address
* DNS_EAI_ALLDONE mark end of the resolving, info is set to NULL in
* this case
* DNS_EAI_CANCELED if the query was canceled manually or timeout happened
* DNS_EAI_FAIL if the name cannot be resolved by the server
* DNS_EAI_NODATA if there is no such name
* other values means that an error happened.
* @param info Query results are stored here.
* @param user_data The user data given in dns_resolve_name() call.
*/
typedef void (*dns_resolve_cb_t)(enum dns_resolve_status status,
struct dns_addrinfo *info,
void *user_data);
/**
* DNS resolve context structure.
*/
struct dns_resolve_context {
struct {
/** DNS server information */
struct sockaddr dns_server;
/** Connection to the DNS server */
struct net_context *net_ctx;
} servers[CONFIG_DNS_RESOLVER_MAX_SERVERS];
/** This timeout is also used when a buffer is required from the
* buffer pools.
*/
int32_t buf_timeout;
/** Result callbacks. We have multiple callbacks here so that it is
* possible to do multiple queries at the same time.
*/
struct dns_pending_query {
/** Timeout timer */
struct k_delayed_work timer;
/** Back pointer to ctx, needed in timeout handler */
struct dns_resolve_context *ctx;
/** Result callback */
dns_resolve_cb_t cb;
/** User data */
void *user_data;
/** TX timeout */
int32_t timeout;
/** String containing the thing to resolve like www.example.com
*/
const char *query;
/** Query type */
enum dns_query_type query_type;
/** DNS id of this query */
uint16_t id;
} queries[CONFIG_DNS_NUM_CONCUR_QUERIES];
/** Is this context in use */
bool is_used;
};
/**
* @brief Init DNS resolving context.
*
* @details This function sets the DNS server address and initializes the
* DNS context that is used by the actual resolver.
* Note that the recommended way to resolve DNS names is to use
* the dns_get_addr_info() API. In that case user does not need to
* call dns_resolve_init() as the DNS servers are already setup by the system.
*
* @param ctx DNS context. If the context variable is allocated from
* the stack, then the variable needs to be valid for the whole duration of
* the resolving. Caller does not need to fill the variable beforehand or
* edit the context afterwards.
* @param server_array DNS server addresses. The array is null terminated.
* The port number can be given in the string.
* Syntax for the server addresses with or without port numbers:
* IPv4 : 10.0.9.1
* IPv4 + port : 10.0.9.1:5353
* IPv6 : 2001:db8::22:42
* IPv6 + port : [2001:db8::22:42]:5353
*
* @return 0 if ok, <0 if error.
*/
int dns_resolve_init(struct dns_resolve_context *ctx,
const char *dns_servers[]);
/**
* @brief Close DNS resolving context.
*
* @details This releases DNS resolving context and marks the context unusable.
* Caller must call the dns_resolve_init() again to make context usable.
*
* @param ctx DNS context
*
* @return 0 if ok, <0 if error.
*/
int dns_resolve_close(struct dns_resolve_context *ctx);
/**
* @brief Cancel a pending DNS query.
*
* @details This releases DNS resources used by a pending query.
*
* @param ctx DNS context
* @param dns_id DNS id of the pending query
*
* @return 0 if ok, <0 if error.
*/
int dns_resolve_cancel(struct dns_resolve_context *ctx,
uint16_t dns_id);
/**
* @brief Resolve DNS name.
*
* @details This function can be used to resolve e.g., IPv4 or IPv6 address.
* Note that this is asynchronous call, the function will return immediately
* and system will call the callback after resolving has finished or timeout
* has occurred.
* We might send the query to multiple servers (if there are more than one
* server configured), but we only use the result of the first received
* response.
*
* @param ctx DNS context
* @param query What the caller wants to resolve.
* @param type What kind of data the caller wants to get.
* @param dns_id DNS id is returned to the caller. This is needed if one
* wishes to cancel the query. This can be set to NULL if there is no need
* to cancel the query.
* @param cb Callback to call after the resolving has finished or timeout
* has happened.
* @param user_data The user data.
* @param timeout The timeout value for the query. Possible values:
* K_FOREVER: the query is tried forever, user needs to cancel it manually
* if it takes too long time to finish
* >0: start the query and let the system timeout it after specified ms
*
* @return 0 if resolving was started ok, < 0 otherwise
*/
int dns_resolve_name(struct dns_resolve_context *ctx,
const char *query,
enum dns_query_type type,
uint16_t *dns_id,
dns_resolve_cb_t cb,
void *user_data,
int32_t timeout);
/**
* @brief Get default DNS context.
*
* @detail The system level DNS context uses DNS servers that are
* defined in project config file. If no DNS servers are defined by the
* user, then resolving DNS names using default DNS context will do nothing.
* The configuration options are described in subsys/net/lib/dns/Kconfig file.
*
* @return Default DNS context.
*/
struct dns_resolve_context *dns_resolve_get_default(void);
/**
* @brief Get IP address info from DNS.
*
* @details This function can be used to resolve e.g., IPv4 or IPv6 address.
* Note that this is asynchronous call, the function will return immediately
* and system will call the callback after resolving has finished or timeout
* has occurred.
* We might send the query to multiple servers (if there are more than one
* server configured), but we only use the result of the first received
* response.
* This variant uses system wide DNS servers.
*
* @param query What the caller wants to resolve.
* @param type What kind of data the caller wants to get.
* @param dns_id DNS id is returned to the caller. This is needed if one
* wishes to cancel the query. This can be set to NULL if there is no need
* to cancel the query.
* @param cb Callback to call after the resolving has finished or timeout
* has happened.
* @param user_data The user data.
* @param timeout The timeout value for the connection. Possible values:
* K_FOREVER: the query is tried forever, user needs to cancel it manually
* if it takes too long time to finish
* >0: start the query and let the system timeout it after specified ms
*
* @return 0 if resolving was started ok, < 0 otherwise
*/
static inline int dns_get_addr_info(const char *query,
enum dns_query_type type,
uint16_t *dns_id,
dns_resolve_cb_t cb,
void *user_data,
int32_t timeout)
{
return dns_resolve_name(dns_resolve_get_default(),
query,
type,
dns_id,
cb,
user_data,
timeout);
}
/**
* @brief Cancel a pending DNS query.
*
* @details This releases DNS resources used by a pending query.
*
* @param dns_id DNS id of the pending query
*
* @return 0 if ok, <0 if error.
*/
static inline int dns_cancel_addr_info(uint16_t dns_id)
{
return dns_resolve_cancel(dns_resolve_get_default(), dns_id);
}
/**
* @brief Initialize DNS subsystem.
*/
void dns_init_resolver(void);
#else
#define dns_init_resolver(...)
#endif /* CONFIG_DNS_RESOLVER */
#endif /* _DNS_RESOLVE_H */

View file

@ -76,6 +76,10 @@ struct net_nbuf {
#if defined(CONFIG_NET_TCP)
bool buf_sent; /* Is this net_buf sent or not */
#endif
#if defined(CONFIG_NET_ROUTE)
bool forwarding; /* Are we forwarding this buf */
#endif
/* @endcond */
};
@ -218,6 +222,23 @@ static inline void net_nbuf_set_buf_sent(struct net_buf *buf, bool sent)
}
#endif
#if defined(CONFIG_NET_ROUTE)
static inline bool net_nbuf_forwarding(struct net_buf *buf)
{
return ((struct net_nbuf *)net_buf_user_data(buf))->forwarding;
}
static inline void net_nbuf_set_forwarding(struct net_buf *buf, bool forward)
{
((struct net_nbuf *)net_buf_user_data(buf))->forwarding = forward;
}
#else
static inline bool net_nbuf_forwarding(struct net_buf *buf)
{
return false;
}
#endif
static inline uint16_t net_nbuf_get_len(struct net_buf *buf)
{
return buf->len;

View file

@ -48,6 +48,8 @@ enum net_event_ipv6_cmd {
NET_EVENT_IPV6_CMD_PREFIX_DEL,
NET_EVENT_IPV6_CMD_MCAST_JOIN,
NET_EVENT_IPV6_CMD_MCAST_LEAVE,
NET_EVENT_IPV6_CMD_ROUTER_ADD,
NET_EVENT_IPV6_CMD_ROUTER_DEL,
};
#define NET_EVENT_IPV6_ADDR_ADD \
@ -74,6 +76,12 @@ enum net_event_ipv6_cmd {
#define NET_EVENT_IPV6_MCAST_LEAVE \
(_NET_EVENT_IPV6_BASE | NET_EVENT_IPV6_CMD_MCAST_LEAVE)
#define NET_EVENT_IPV6_ROUTER_ADD \
(_NET_EVENT_IPV6_BASE | NET_EVENT_IPV6_CMD_ROUTER_ADD)
#define NET_EVENT_IPV6_ROUTER_DEL \
(_NET_EVENT_IPV6_BASE | NET_EVENT_IPV6_CMD_ROUTER_DEL)
/* IPv4 Events*/
#define _NET_IPV4_LAYER NET_MGMT_LAYER_L3
#define _NET_IPV4_CORE_CODE 0x400

View file

@ -162,6 +162,11 @@ enum {
NET_IF_NUM_FLAGS
};
#if defined(CONFIG_NET_OFFLOAD)
struct net_offload;
#endif /* CONFIG_NET_OFFLOAD */
/**
* @brief Network Interface structure
*
@ -194,11 +199,14 @@ struct net_if {
/** The hardware MTU */
uint16_t mtu;
/** Is the IP stack is offloaded. If set, then the IP stack is located
* in the communication chip that is accessed via this network
* interface.
#if defined(CONFIG_NET_OFFLOAD)
/** TCP/IP Offload functions.
* If non-NULL, then the TCP/IP stack is located
* in the communication chip that is accessed via this
* network interface.
*/
bool offload_ip;
struct net_offload *offload;
#endif /* CONFIG_NET_OFFLOAD */
/** Queue for outgoing packets from apps */
struct k_fifo tx_queue;
@ -379,6 +387,7 @@ static inline void net_if_queue_tx(struct net_if *iface, struct net_buf *buf)
net_buf_put(&iface->tx_queue, buf);
}
#if defined(CONFIG_NET_OFFLOAD)
/**
* @brief Return the IP offload status.
*
@ -388,8 +397,9 @@ static inline void net_if_queue_tx(struct net_if *iface, struct net_buf *buf)
*/
static inline bool net_if_is_ip_offloaded(struct net_if *iface)
{
return iface->offload_ip;
return (iface->offload != NULL);
}
#endif
/**
* @brief Get an network interface's link address

View file

@ -20,10 +20,6 @@ extern "C" {
struct net_if;
#if defined(CONFIG_NET_L2_OFFLOAD_IP)
struct net_l2_offload_ip;
#endif /* CONFIG_NET_L2_OFFLOAD_IP */
struct net_l2 {
/**
* This function is used by net core to get iface's L2 layer parsing
@ -50,10 +46,6 @@ struct net_l2 {
* interface.
*/
int (*enable)(struct net_if *iface, bool state);
#if defined(CONFIG_NET_L2_OFFLOAD_IP)
struct net_l2_offload_ip *offload_ip;
#endif /* CONFIG_NET_L2_OFFLOAD_IP */
};
#define NET_L2_GET_NAME(_name) (__net_l2_##_name)
@ -87,10 +79,10 @@ NET_L2_DECLARE_PUBLIC(IEEE802154_L2);
#define BLUETOOTH_L2_CTX_TYPE void*
#endif /* CONFIG_NET_L2_BLUETOOTH */
#ifdef CONFIG_NET_L2_OFFLOAD_IP
#ifdef CONFIG_NET_OFFLOAD
#define OFFLOAD_IP_L2 OFFLOAD_IP
#define OFFLOAD_IP_L2_CTX_TYPE void*
#endif /* CONFIG_NET_L2_OFFLOAD_IP */
#endif /* CONFIG_NET_OFFLOAD */
extern struct net_l2 __net_l2_end[];

View file

@ -9,10 +9,10 @@
* @brief Public API for offloading IP stack
*/
#ifndef __OFFLOAD_IP_H__
#define __OFFLOAD_IP_H__
#ifndef __NET_OFFLOAD_H__
#define __NET_OFFLOAD_H__
#if defined(CONFIG_NET_L2_OFFLOAD_IP)
#if defined(CONFIG_NET_OFFLOAD)
#include <net/buf.h>
#include <net/net_ip.h>
@ -25,7 +25,7 @@ extern "C" {
/** For return parameters and return values of the elements in this
* struct, see similarly named functions in net_context.h
*/
struct net_l2_offload_ip {
struct net_offload {
/**
* This function is called when the socket is to be opened.
*/
@ -119,18 +119,17 @@ struct net_l2_offload_ip {
*
* @return 0 if ok, < 0 if error
*/
static inline int net_l2_offload_ip_get(struct net_if *iface,
static inline int net_offload_get(struct net_if *iface,
sa_family_t family,
enum net_sock_type type,
enum net_ip_protocol ip_proto,
struct net_context **context)
{
NET_ASSERT(iface);
NET_ASSERT(iface->l2);
NET_ASSERT(iface->l2->offload_ip);
NET_ASSERT(iface->l2->offload_ip->get);
NET_ASSERT(iface->offload);
NET_ASSERT(iface->offload->get);
return iface->l2->offload_ip->get(family, type, ip_proto, context);
return iface->offload->get(family, type, ip_proto, context);
}
/**
@ -146,17 +145,16 @@ static inline int net_l2_offload_ip_get(struct net_if *iface,
*
* @return 0 if ok, < 0 if error
*/
static inline int net_l2_offload_ip_bind(struct net_if *iface,
static inline int net_offload_bind(struct net_if *iface,
struct net_context *context,
const struct sockaddr *addr,
socklen_t addrlen)
{
NET_ASSERT(iface);
NET_ASSERT(iface->l2);
NET_ASSERT(iface->l2->offload_ip);
NET_ASSERT(iface->l2->offload_ip->bind);
NET_ASSERT(iface->offload);
NET_ASSERT(iface->offload->bind);
return iface->l2->offload_ip->bind(context, addr, addrlen);
return iface->offload->bind(context, addr, addrlen);
}
/**
@ -171,16 +169,15 @@ static inline int net_l2_offload_ip_bind(struct net_if *iface,
*
* @return 0 if ok, < 0 if error
*/
static inline int net_l2_offload_ip_listen(struct net_if *iface,
static inline int net_offload_listen(struct net_if *iface,
struct net_context *context,
int backlog)
{
NET_ASSERT(iface);
NET_ASSERT(iface->l2);
NET_ASSERT(iface->l2->offload_ip);
NET_ASSERT(iface->l2->offload_ip->listen);
NET_ASSERT(iface->offload);
NET_ASSERT(iface->offload->listen);
return iface->l2->offload_ip->listen(context, backlog);
return iface->offload->listen(context, backlog);
}
/**
@ -212,7 +209,7 @@ static inline int net_l2_offload_ip_listen(struct net_if *iface,
* @return -EINVAL if an invalid parameter is passed as an argument.
* @return -ENOTSUP if the operation is not supported or implemented.
*/
static inline int net_l2_offload_ip_connect(struct net_if *iface,
static inline int net_offload_connect(struct net_if *iface,
struct net_context *context,
const struct sockaddr *addr,
socklen_t addrlen,
@ -221,11 +218,10 @@ static inline int net_l2_offload_ip_connect(struct net_if *iface,
void *user_data)
{
NET_ASSERT(iface);
NET_ASSERT(iface->l2);
NET_ASSERT(iface->l2->offload_ip);
NET_ASSERT(iface->l2->offload_ip->connect);
NET_ASSERT(iface->offload);
NET_ASSERT(iface->offload->connect);
return iface->l2->offload_ip->connect(context, addr, addrlen, cb,
return iface->offload->connect(context, addr, addrlen, cb,
timeout, user_data);
}
@ -256,18 +252,17 @@ static inline int net_l2_offload_ip_connect(struct net_if *iface,
*
* @return 0 if ok, < 0 if error
*/
static inline int net_l2_offload_ip_accept(struct net_if *iface,
static inline int net_offload_accept(struct net_if *iface,
struct net_context *context,
net_tcp_accept_cb_t cb,
int32_t timeout,
void *user_data)
{
NET_ASSERT(iface);
NET_ASSERT(iface->l2);
NET_ASSERT(iface->l2->offload_ip);
NET_ASSERT(iface->l2->offload_ip->accept);
NET_ASSERT(iface->offload);
NET_ASSERT(iface->offload->accept);
return iface->l2->offload_ip->accept(context, cb, timeout, user_data);
return iface->offload->accept(context, cb, timeout, user_data);
}
/**
@ -297,7 +292,7 @@ static inline int net_l2_offload_ip_accept(struct net_if *iface,
*
* @return 0 if ok, < 0 if error
*/
static inline int net_l2_offload_ip_send(struct net_if *iface,
static inline int net_offload_send(struct net_if *iface,
struct net_buf *buf,
net_context_send_cb_t cb,
int32_t timeout,
@ -305,11 +300,10 @@ static inline int net_l2_offload_ip_send(struct net_if *iface,
void *user_data)
{
NET_ASSERT(iface);
NET_ASSERT(iface->l2);
NET_ASSERT(iface->l2->offload_ip);
NET_ASSERT(iface->l2->offload_ip->send);
NET_ASSERT(iface->offload);
NET_ASSERT(iface->offload->send);
return iface->l2->offload_ip->send(buf, cb, timeout, token, user_data);
return iface->offload->send(buf, cb, timeout, token, user_data);
}
/**
@ -341,7 +335,7 @@ static inline int net_l2_offload_ip_send(struct net_if *iface,
*
* @return 0 if ok, < 0 if error
*/
static inline int net_l2_offload_ip_sendto(struct net_if *iface,
static inline int net_offload_sendto(struct net_if *iface,
struct net_buf *buf,
const struct sockaddr *dst_addr,
socklen_t addrlen,
@ -351,11 +345,10 @@ static inline int net_l2_offload_ip_sendto(struct net_if *iface,
void *user_data)
{
NET_ASSERT(iface);
NET_ASSERT(iface->l2);
NET_ASSERT(iface->l2->offload_ip);
NET_ASSERT(iface->l2->offload_ip->sendto);
NET_ASSERT(iface->offload);
NET_ASSERT(iface->offload->sendto);
return iface->l2->offload_ip->sendto(buf, dst_addr, addrlen, cb,
return iface->offload->sendto(buf, dst_addr, addrlen, cb,
timeout, token, user_data);
}
@ -392,18 +385,17 @@ static inline int net_l2_offload_ip_sendto(struct net_if *iface,
*
* @return 0 if ok, < 0 if error
*/
static inline int net_l2_offload_ip_recv(struct net_if *iface,
static inline int net_offload_recv(struct net_if *iface,
struct net_context *context,
net_context_recv_cb_t cb,
int32_t timeout,
void *user_data)
{
NET_ASSERT(iface);
NET_ASSERT(iface->l2);
NET_ASSERT(iface->l2->offload_ip);
NET_ASSERT(iface->l2->offload_ip->recv);
NET_ASSERT(iface->offload);
NET_ASSERT(iface->offload->recv);
return iface->l2->offload_ip->recv(context, cb, timeout, user_data);
return iface->offload->recv(context, cb, timeout, user_data);
}
/**
@ -419,21 +411,20 @@ static inline int net_l2_offload_ip_recv(struct net_if *iface,
*
* @return 0 if ok, < 0 if error
*/
static inline int net_l2_offload_ip_put(struct net_if *iface,
static inline int net_offload_put(struct net_if *iface,
struct net_context *context)
{
NET_ASSERT(iface);
NET_ASSERT(iface->l2);
NET_ASSERT(iface->l2->offload_ip);
NET_ASSERT(iface->l2->offload_ip->put);
NET_ASSERT(iface->offload);
NET_ASSERT(iface->offload->put);
return iface->l2->offload_ip->put(context);
return iface->offload->put(context);
}
#ifdef __cplusplus
}
#endif
#endif /* CONFIG_NET_L2_OFFLOAD_IP */
#endif /* CONFIG_NET_OFFLOAD */
#endif /* __OFFLOAD_IP_H__ */
#endif /* __NET_OFFLOAD_H__ */

View file

@ -0,0 +1,13 @@
#
# Copyright (c) 2016 Intel Corporation
#
# SPDX-License-Identifier: Apache-2.0
#
BOARD ?= qemu_x86
CONF_FILE ?= prj_$(BOARD).conf
include $(ZEPHYR_BASE)/Makefile.inc
ifeq ($(BOARD), qemu_x86)
include $(ZEPHYR_BASE)/samples/net/common/Makefile.ipstack
endif

View file

@ -0,0 +1,59 @@
CONFIG_NETWORKING=y
CONFIG_NET_UDP=y
CONFIG_RANDOM_GENERATOR=y
CONFIG_TEST_RANDOM_GENERATOR=y
CONFIG_NET_SLIP_TAP=y
CONFIG_INIT_STACKS=y
CONFIG_NET_NBUF_RX_COUNT=4
CONFIG_NET_NBUF_TX_COUNT=4
CONFIG_NET_NBUF_RX_DATA_COUNT=14
CONFIG_NET_NBUF_TX_DATA_COUNT=14
CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=3
CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=5
CONFIG_NET_LOG=y
CONFIG_SYS_LOG=y
CONFIG_SYS_LOG_NET_LEVEL=4
CONFIG_SYS_LOG_SHOW_COLOR=y
#CONFIG_NET_DEBUG_NET_BUF=y
CONFIG_NET_DEBUG_DNS_RESOLVE=y
#CONFIG_NET_DEBUG_CONTEXT=y
#CONFIG_NET_DEBUG_CORE=y
#CONFIG_NET_DEBUG_IF=y
#CONFIG_NET_DEBUG_IPV4=y
#CONFIG_NET_DEBUG_IPV6=y
#CONFIG_NET_DEBUG_UDP=y
#CONFIG_NET_DEBUG_DHCPV4=y
#CONFIG_SLIP_DEBUG=y
CONFIG_NET_IPV4=y
CONFIG_NET_IPV6=y
# Enable the DNS resolver
CONFIG_DNS_RESOLVER=y
# Enable additional buffers
CONFIG_DNS_RESOLVER_ADDITIONAL_BUF_CTR=2
# Enable additional queries
CONFIG_DNS_RESOLVER_ADDITIONAL_QUERIES=2
CONFIG_DNS_RESOLVER_MAX_SERVERS=2
CONFIG_DNS_SERVER_IP_ADDRESSES=y
CONFIG_DNS_NUM_CONCUR_QUERIES=2
# Google DNS IPv4 and IPv6 servers
CONFIG_DNS_SERVER1="8.8.8.8"
CONFIG_DNS_SERVER2="2001:4860:4860::8888"
CONFIG_NET_DHCPV4=y
CONFIG_NET_MGMT=y
CONFIG_NET_MGMT_EVENT=y
CONFIG_NET_SHELL=y
CONFIG_NET_SAMPLES_IP_ADDRESSES=y
CONFIG_NET_SAMPLES_MY_IPV6_ADDR="2001:db8::1"
CONFIG_NET_SAMPLES_PEER_IPV6_ADDR="2001:db8::2"
CONFIG_NET_SAMPLES_MY_IPV4_ADDR="192.0.2.1"
CONFIG_NET_SAMPLES_PEER_IPV4_ADDR="192.0.2.2"

View file

@ -0,0 +1,7 @@
#
# Copyright (c) 2016 Intel Corporation
#
# SPDX-License-Identifier: Apache-2.0
#
obj-y += main.o

View file

@ -0,0 +1,284 @@
/*
* Copyright (c) 2017 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
#if 1
#define SYS_LOG_DOMAIN "dns-res"
#define NET_SYS_LOG_LEVEL SYS_LOG_LEVEL_DEBUG
#define NET_LOG_ENABLED 1
#endif
#include <zephyr.h>
#include <sections.h>
#include <errno.h>
#include <stdio.h>
#include <net/net_core.h>
#include <net/net_if.h>
#include <net/net_mgmt.h>
#include <net/dns_resolve.h>
#define STACKSIZE 2000
char __noinit __stack thread_stack[STACKSIZE];
#define DNS_TIMEOUT 2000 /* ms */
void dns_result_cb(enum dns_resolve_status status,
struct dns_addrinfo *info,
void *user_data)
{
char hr_addr[NET_IPV6_ADDR_LEN];
char *hr_family;
void *addr;
switch (status) {
case DNS_EAI_CANCELED:
NET_INFO("DNS query was canceled");
return;
case DNS_EAI_FAIL:
NET_INFO("DNS resolve failed");
return;
case DNS_EAI_NODATA:
NET_INFO("Cannot resolve address");
return;
case DNS_EAI_ALLDONE:
NET_INFO("DNS resolving finished");
return;
case DNS_EAI_INPROGRESS:
break;
default:
NET_INFO("DNS resolving error (%d)", status);
return;
}
if (!info) {
return;
}
if (info->ai_family == AF_INET) {
hr_family = "IPv4";
addr = &net_sin(&info->ai_addr)->sin_addr;
} else if (info->ai_family == AF_INET6) {
hr_family = "IPv6";
addr = &net_sin6(&info->ai_addr)->sin6_addr;
} else {
NET_ERR("Invalid IP address family %d", info->ai_family);
return;
}
NET_INFO("%s address: %s", hr_family,
net_addr_ntop(info->ai_family, addr,
hr_addr, sizeof(hr_addr)));
}
#if defined(CONFIG_NET_DHCPV4)
static struct net_mgmt_event_callback mgmt4_cb;
static struct k_delayed_work ipv4_timer;
static void do_ipv4_lookup(struct k_work *work)
{
uint16_t dns_id;
int ret;
ret = dns_get_addr_info("www.zephyrproject.org",
DNS_QUERY_TYPE_A,
&dns_id,
dns_result_cb,
NULL,
DNS_TIMEOUT);
if (ret < 0) {
NET_ERR("Cannot resolve IPv4 address (%d)", ret);
return;
}
NET_DBG("DNS id %u", dns_id);
}
static void ipv4_addr_add_handler(struct net_mgmt_event_callback *cb,
uint32_t mgmt_event,
struct net_if *iface)
{
char hr_addr[NET_IPV4_ADDR_LEN];
int i;
if (mgmt_event != NET_EVENT_IPV4_ADDR_ADD) {
return;
}
for (i = 0; i < NET_IF_MAX_IPV4_ADDR; i++) {
struct net_if_addr *if_addr = &iface->ipv4.unicast[i];
if (if_addr->addr_type != NET_ADDR_DHCP || !if_addr->is_used) {
continue;
}
NET_INFO("IPv4 address: %s",
net_addr_ntop(AF_INET, &if_addr->address.in_addr,
hr_addr, NET_IPV4_ADDR_LEN));
NET_INFO("Lease time: %u seconds", iface->dhcpv4.lease_time);
NET_INFO("Subnet: %s",
net_addr_ntop(AF_INET, &iface->ipv4.netmask,
hr_addr, NET_IPV4_ADDR_LEN));
NET_INFO("Router: %s",
net_addr_ntop(AF_INET, &iface->ipv4.gw,
hr_addr, NET_IPV4_ADDR_LEN));
break;
}
/* We cannot run DNS lookup directly from this thread as the
* management event thread stack is very small by default.
* So run it from work queue instead.
*/
k_delayed_work_init(&ipv4_timer, do_ipv4_lookup);
k_delayed_work_submit(&ipv4_timer, 0);
}
static void setup_dhcpv4(struct net_if *iface)
{
NET_INFO("Running dhcpv4 client...");
net_mgmt_init_event_callback(&mgmt4_cb, ipv4_addr_add_handler,
NET_EVENT_IPV4_ADDR_ADD);
net_mgmt_add_event_callback(&mgmt4_cb);
net_dhcpv4_start(iface);
}
#else
#define setup_dhcpv4(...)
#endif /* CONFIG_NET_DHCPV4 */
#if defined(CONFIG_NET_IPV4) && !defined(CONFIG_NET_DHCPV4)
#if !defined(CONFIG_NET_SAMPLES_MY_IPV4_ADDR)
#error "You need to define an IPv4 address or enable DHCPv4!"
#endif
static void setup_ipv4(struct net_if *iface)
{
char hr_addr[NET_IPV4_ADDR_LEN];
struct in_addr addr;
uint16_t dns_id;
int ret;
if (net_addr_pton(AF_INET, CONFIG_NET_SAMPLES_MY_IPV4_ADDR, &addr)) {
NET_ERR("Invalid address: %s", CONFIG_NET_SAMPLES_MY_IPV4_ADDR);
return;
}
net_if_ipv4_addr_add(iface, &addr, NET_ADDR_MANUAL, 0);
NET_INFO("IPv4 address: %s",
net_addr_ntop(AF_INET, &addr, hr_addr, NET_IPV4_ADDR_LEN));
ret = dns_get_addr_info("www.zephyrproject.org",
DNS_QUERY_TYPE_A,
&dns_id,
dns_result_cb,
NULL,
DNS_TIMEOUT);
if (ret < 0) {
NET_ERR("Cannot resolve IPv4 address (%d)", ret);
return;
}
NET_DBG("DNS id %u", dns_id);
}
#else
#define setup_ipv4(...)
#endif /* CONFIG_NET_IPV4 && !CONFIG_NET_DHCPV4 */
#if defined(CONFIG_NET_IPV6)
#if !defined(CONFIG_NET_SAMPLES_MY_IPV6_ADDR)
#error "You need to define an IPv6 address!"
#endif
static struct net_mgmt_event_callback mgmt6_cb;
static struct k_delayed_work ipv6_timer;
static void do_ipv6_lookup(struct k_work *work)
{
uint16_t dns_id;
int ret;
ret = dns_get_addr_info("www.zephyrproject.org",
DNS_QUERY_TYPE_AAAA,
&dns_id,
dns_result_cb,
NULL,
DNS_TIMEOUT);
if (ret < 0) {
NET_ERR("Cannot resolve IPv6 address (%d)", ret);
return;
}
NET_DBG("DNS id %u", dns_id);
}
/* DNS query will most probably fail if we do not have a default
* router configured because typically the DNS server is outside of local
* network. So wait for that before continuing.
*/
static void ipv6_router_add_handler(struct net_mgmt_event_callback *cb,
uint32_t mgmt_event,
struct net_if *iface)
{
if (mgmt_event != NET_EVENT_IPV6_ROUTER_ADD) {
return;
}
/* We cannot run DNS lookup directly from this thread as the
* management event thread stack is very small by default.
* So run it from work queue instead.
*/
k_delayed_work_init(&ipv6_timer, do_ipv6_lookup);
k_delayed_work_submit(&ipv6_timer, 0);
}
static void setup_ipv6(struct net_if *iface)
{
char hr_addr[NET_IPV6_ADDR_LEN];
struct in6_addr addr;
if (net_addr_pton(AF_INET6, CONFIG_NET_SAMPLES_MY_IPV6_ADDR, &addr)) {
NET_ERR("Invalid address: %s", CONFIG_NET_SAMPLES_MY_IPV6_ADDR);
return;
}
net_mgmt_init_event_callback(&mgmt6_cb, ipv6_router_add_handler,
NET_EVENT_IPV6_ROUTER_ADD);
net_mgmt_add_event_callback(&mgmt6_cb);
net_if_ipv6_addr_add(iface, &addr, NET_ADDR_MANUAL, 0);
NET_INFO("IPv6 address: %s",
net_addr_ntop(AF_INET6, &addr, hr_addr, NET_IPV6_ADDR_LEN));
}
#else
#define setup_ipv6(...)
#endif /* CONFIG_NET_IPV6 */
static void network_setup(void)
{
struct net_if *iface = net_if_get_default();
setup_ipv4(iface);
setup_dhcpv4(iface);
setup_ipv6(iface);
}
void main(void)
{
NET_INFO("Starting DNS resolve sample");
k_thread_spawn(&thread_stack[0], STACKSIZE,
(k_thread_entry_t)network_setup,
NULL, NULL, NULL, K_PRIO_COOP(7), 0, 0);
}

View file

@ -0,0 +1,4 @@
[test]
tags = net dns
build_only = true
platform_whitelist = qemu_x86

View file

@ -26,3 +26,7 @@ CONFIG_ETH_ENC28J60_0_MAC5=0x32
# Arduino 101
CONFIG_SPI=y
CONFIG_NET_SAMPLES_IP_ADDRESSES=y
CONFIG_NET_SAMPLES_MY_IPV4_ADDR="192.0.2.2"
CONFIG_NET_SAMPLES_PEER_IPV4_ADDR="192.0.2.1"

View file

@ -0,0 +1,32 @@
# For Freedom board with ethernet support
CONFIG_NETWORKING=y
CONFIG_NET_LOG=y
CONFIG_NET_IPV6=y
CONFIG_NET_IPV4=y
CONFIG_NET_DHCPV4=n
CONFIG_NET_UDP=y
CONFIG_NET_TCP=y
CONFIG_NET_STATISTICS=y
CONFIG_NET_NBUF_RX_COUNT=14
CONFIG_NET_NBUF_TX_COUNT=14
CONFIG_NET_NBUF_RX_DATA_COUNT=30
CONFIG_NET_NBUF_TX_DATA_COUNT=30
CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=5
CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=5
CONFIG_NET_IF_UNICAST_IPV4_ADDR_COUNT=1
CONFIG_NET_MAX_CONTEXTS=10
CONFIG_INIT_STACKS=y
CONFIG_SYS_LOG_SHOW_COLOR=y
CONFIG_PRINTK=y
CONFIG_NET_L2_ETHERNET=y
CONFIG_NET_SHELL=y
CONFIG_NET_SAMPLES_IP_ADDRESSES=y
CONFIG_NET_SAMPLES_MY_IPV6_ADDR="2001:db8::1"
CONFIG_NET_SAMPLES_PEER_IPV6_ADDR="2001:db8::2"
CONFIG_NET_SAMPLES_MY_IPV4_ADDR="192.0.2.1"
CONFIG_NET_SAMPLES_PEER_IPV4_ADDR="192.0.2.2"

View file

@ -0,0 +1,36 @@
# For Atmel SMART SAM E70 Xplained board
CONFIG_NETWORKING=y
CONFIG_NET_LOG=y
CONFIG_NET_IPV6=y
CONFIG_NET_IPV4=y
CONFIG_NET_DHCPV4=n
CONFIG_NET_UDP=y
CONFIG_NET_TCP=y
CONFIG_NET_STATISTICS=n
CONFIG_NET_NBUF_RX_COUNT=14
CONFIG_NET_NBUF_TX_COUNT=14
CONFIG_NET_NBUF_RX_DATA_COUNT=36
CONFIG_NET_NBUF_TX_DATA_COUNT=36
CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=2
CONFIG_NET_IF_UNICAST_IPV4_ADDR_COUNT=1
CONFIG_NET_MAX_CONTEXTS=10
CONFIG_NET_L2_ETHERNET=y
CONFIG_INIT_STACKS=y
CONFIG_TEST_RANDOM_GENERATOR=y
CONFIG_SYS_LOG_SHOW_COLOR=y
CONFIG_PRINTK=y
CONFIG_ETH_INIT_PRIORITY=95
CONFIG_ETH_SAM_GMAC=y
CONFIG_ETH_SAM_GMAC_MAC0=10
CONFIG_ETH_SAM_GMAC_MAC1=22
CONFIG_ETH_SAM_GMAC_MAC2=33
CONFIG_ETH_SAM_GMAC_MAC3=44
CONFIG_ETH_SAM_GMAC_MAC4=55
CONFIG_ETH_SAM_GMAC_MAC5=66
CONFIG_NET_SAMPLES_IP_ADDRESSES=y
CONFIG_NET_SAMPLES_MY_IPV6_ADDR="2001:db8::1"
CONFIG_NET_SAMPLES_MY_IPV4_ADDR="192.0.2.1"

View file

@ -130,10 +130,6 @@ static bool send_tcp_data(struct net_context *ctx,
#endif /* CONFIG_NET_TCP */
#if defined(CONFIG_NET_IPV6)
/* admin-local, dynamically allocated multicast address */
#define MCAST_IP6ADDR { { { 0xff, 0x84, 0, 0, 0, 0, 0, 0, \
0, 0, 0, 0, 0, 0, 0, 0x2 } } }
/* Define the peer IP address where to send messages */
#define PEER_IP6ADDR { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, \
0, 0, 0, 0, 0, 0, 0, 0x2 } } }
@ -148,8 +144,6 @@ static struct in6_addr in6addr_my = MY_IP6ADDR;
static struct in6_addr in6addr_peer = PEER_IP6ADDR;
#endif
static struct in6_addr in6addr_mcast = MCAST_IP6ADDR;
static struct sockaddr_in6 my_addr6 = {
.sin6_family = AF_INET6,
.sin6_port = htons(MY_PORT),
@ -160,11 +154,6 @@ static struct sockaddr_in6 peer_addr6 = {
.sin6_port = htons(PEER_PORT),
};
static struct sockaddr_in6 mcast_addr6 = {
.sin6_family = AF_INET6,
.sin6_port = htons(PEER_PORT),
};
#if defined(CONFIG_NET_UDP)
static char __noinit __stack ipv6_udp_stack[STACKSIZE];
#endif
@ -176,9 +165,6 @@ static char __noinit __stack ipv6_tcp_stack[STACKSIZE];
#endif /* CONFIG_NET_IPV6 */
#if defined(CONFIG_NET_IPV4)
/* Organization-local 239.192.0.0/14 */
#define MCAST_IP4ADDR { { { 239, 192, 0, 2 } } }
#define MY_IP4ADDR { { { 192, 0, 2, 1 } } }
#define PEER_IP4ADDR { { { 192, 0, 2, 2 } } }
@ -248,9 +234,6 @@ static inline void init_app(void)
NET_ADDR_MANUAL, 0);
} while (0);
net_ipaddr_copy(&mcast_addr6.sin6_addr, &in6addr_mcast);
net_if_ipv6_maddr_add(net_if_get_default(), &in6addr_mcast);
#if defined(CONFIG_NET_UDP)
k_sem_init(&conf.recv_ipv6, 0, UINT_MAX);
#endif
@ -295,8 +278,7 @@ static inline void init_app(void)
static inline bool get_context(struct net_context **udp_recv4,
struct net_context **udp_recv6,
struct net_context **tcp_recv4,
struct net_context **tcp_recv6,
struct net_context **mcast_recv6)
struct net_context **tcp_recv6)
{
int ret;
@ -317,22 +299,6 @@ static inline bool get_context(struct net_context **udp_recv4,
ntohs(my_addr6.sin6_port), ret);
return false;
}
ret = net_context_get(AF_INET6, SOCK_DGRAM, IPPROTO_UDP, mcast_recv6);
if (ret < 0) {
NET_ERR("Cannot get receiving IPv6 mcast "
"network context (%d)", ret);
return false;
}
net_context_setup_pools(*mcast_recv6, tx_udp_pool, data_udp_pool);
ret = net_context_bind(*mcast_recv6, (struct sockaddr *)&mcast_addr6,
sizeof(struct sockaddr_in6));
if (ret < 0) {
NET_ERR("Cannot bind IPv6 mcast (%d)", ret);
return false;
}
#endif
#if defined(CONFIG_NET_IPV4) && defined(CONFIG_NET_UDP)
@ -889,13 +855,11 @@ static void event_iface_up(struct net_mgmt_event_callback *cb,
struct net_context *udp_send6 = { 0 };
struct net_context *tcp_send4 = { 0 };
struct net_context *tcp_send6 = { 0 };
struct net_context *mcast_send6 = { 0 };
ipsum_len = strlen(lorem_ipsum);
if (!get_context(&udp_send4, &udp_send6,
&tcp_send4, &tcp_send6,
&mcast_send6)) {
&tcp_send4, &tcp_send6)) {
NET_ERR("Cannot get network contexts");
return;
}

View file

@ -26,3 +26,7 @@ CONFIG_ETH_ENC28J60_0_MAC5=0x36
# Arduino 101
CONFIG_SPI=y
CONFIG_NET_SAMPLES_IP_ADDRESSES=y
CONFIG_NET_SAMPLES_MY_IPV4_ADDR="192.0.2.1"
CONFIG_NET_SAMPLES_PEER_IPV4_ADDR="192.0.2.2"

View file

@ -30,12 +30,6 @@
#define NET_BIND_ANY_ADDR 1
#if defined(CONFIG_NET_IPV6)
/* admin-local, dynamically allocated multicast address */
#define MCAST_IP6ADDR { { { 0xff, 0x84, 0, 0, 0, 0, 0, 0, \
0, 0, 0, 0, 0, 0, 0, 0x2 } } }
struct in6_addr in6addr_mcast = MCAST_IP6ADDR;
/* Define my IP address where to expect messages */
#define MY_IP6ADDR { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, \
0, 0, 0, 0, 0, 0, 0, 0x1 } } }
@ -45,9 +39,6 @@ static struct in6_addr in6addr_my = MY_IP6ADDR;
#endif /* IPv6 */
#if defined(CONFIG_NET_IPV4)
/* Organization-local 239.192.0.0/14 */
#define MCAST_IP4ADDR { { { 239, 192, 0, 2 } } }
/* The 192.0.2.0/24 is the private address space for documentation RFC 5737 */
#define MY_IP4ADDR { { { 192, 0, 2, 1 } } }
@ -127,8 +118,6 @@ static inline void init_app(void)
ifaddr = net_if_ipv6_addr_add(net_if_get_default(),
&in6addr_my, NET_ADDR_MANUAL, 0);
} while (0);
net_if_ipv6_maddr_add(net_if_get_default(), &in6addr_mcast);
#endif
#if defined(CONFIG_NET_IPV4)
@ -153,13 +142,11 @@ static inline void init_app(void)
static inline bool get_context(struct net_context **udp_recv4,
struct net_context **udp_recv6,
struct net_context **tcp_recv4,
struct net_context **tcp_recv6,
struct net_context **mcast_recv6)
struct net_context **tcp_recv6)
{
int ret;
#if defined(CONFIG_NET_IPV6)
struct sockaddr_in6 mcast_addr6 = { 0 };
struct sockaddr_in6 my_addr6 = { 0 };
#endif
@ -168,9 +155,6 @@ static inline bool get_context(struct net_context **udp_recv4,
#endif
#if defined(CONFIG_NET_IPV6)
net_ipaddr_copy(&mcast_addr6.sin6_addr, &in6addr_mcast);
mcast_addr6.sin6_family = AF_INET6;
#if !NET_BIND_ANY_ADDR
net_ipaddr_copy(&my_addr6.sin6_addr, &in6addr_my);
#endif
@ -205,20 +189,6 @@ static inline bool get_context(struct net_context **udp_recv4,
ntohs(my_addr6.sin6_port), ret);
return false;
}
ret = net_context_get(AF_INET6, SOCK_DGRAM, IPPROTO_UDP, mcast_recv6);
if (ret < 0) {
NET_ERR("Cannot get receiving IPv6 mcast "
"network context (%d)", ret);
return false;
}
ret = net_context_bind(*mcast_recv6, (struct sockaddr *)&mcast_addr6,
sizeof(struct sockaddr_in6));
if (ret < 0) {
NET_ERR("Cannot bind IPv6 mcast (%d)", ret);
return false;
}
#endif
#if defined(CONFIG_NET_IPV4) && defined(CONFIG_NET_UDP)
@ -549,11 +519,9 @@ void receive(void)
struct net_context *udp_recv6 = { 0 };
struct net_context *tcp_recv4 = { 0 };
struct net_context *tcp_recv6 = { 0 };
struct net_context *mcast_recv6 = { 0 };
if (!get_context(&udp_recv4, &udp_recv6,
&tcp_recv4, &tcp_recv6,
&mcast_recv6)) {
&tcp_recv4, &tcp_recv6)) {
NET_ERR("Cannot get network contexts");
return;
}
@ -574,7 +542,6 @@ void receive(void)
#if defined(CONFIG_NET_IPV6) && defined(CONFIG_NET_UDP)
net_context_put(udp_recv6);
net_context_put(mcast_recv6);
#endif
#if defined(CONFIG_NET_IPV4) && defined(CONFIG_NET_UDP)

View file

@ -10,6 +10,7 @@ CONFIG_SERIAL=y
CONFIG_UART_INTERRUPT_DRIVEN=y
CONFIG_UART_LINE_CTRL=y
CONFIG_IEEE802154_CC2520=y
CONFIG_IEEE802154_CC2520_RAW=y
CONFIG_NET_BUF=y
CONFIG_NETWORKING=y

View file

@ -22,7 +22,7 @@
#include <net/buf.h>
#define SYS_LOG_DOMAIN "main"
#define SYS_LOG_DOMAIN "wpan_serial"
#include <logging/sys_log.h>
#include <net_private.h>

View file

@ -15,7 +15,7 @@ CONFIG_NET_NBUF_DATA_SIZE=128
CONFIG_NET_L2_IEEE802154=y
#CONFIG_IEEE802154_CC2520=y
CONFIG_IEEE802154_CC2520=y
CONFIG_IEEE802154_CC2520_RAW=y
CONFIG_SYS_LOG=y

View file

@ -1,9 +1,5 @@
ccflags-y += -I${ZEPHYR_BASE}/usb/include -I${ZEPHYR_BASE}/include/drivers/usb -I${ZEPHYR_BASE}/include/usb/
ccflags-$(CONFIG_IEEE802154_CC2520_LEGACY) += -I${ZEPHYR_BASE}/net/ip/contiki/os
ccflags-$(CONFIG_IEEE802154_CC2520_LEGACY) += -I${ZEPHYR_BASE}/net/ip/contiki
ccflags-$(CONFIG_IEEE802154_CC2520_LEGACY) += -I${ZEPHYR_BASE}/net/ip
ccflags-$(CONFIG_IEEE802154_CC2520_RAW) += -I${ZEPHYR_BASE}/subsys/net/ip
obj-y += wpanusb.o

View file

@ -387,7 +387,7 @@ static int wpanusb_vendor_handler(struct usb_setup_packet *setup,
return -ENOMEM;
}
buf = net_nbuf_get_frag(buf, K_NO_WAIT);
buf = net_nbuf_get_frag(pkt, K_NO_WAIT);
if (!buf) {
net_nbuf_unref(pkt);
return -ENOMEM;

View file

@ -53,11 +53,13 @@ config NET_MAX_ROUTERS
help
The value depends on your network needs.
# Normally the route support is enabled by RPL or similar technology
# that needs to use the routing infrastructure.
config NET_ROUTE
bool
depends on NET_IPV6
depends on NET_IPV6_NBR_CACHE
default n
default y if NET_IPV6
default y if NET_IPV6_NBR_CACHE
config NET_MAX_ROUTES
int "Max number of routing entries stored."

View file

@ -9,7 +9,8 @@
menuconfig NET_RPL
bool "Enable RPL (Ripple) support"
default n
select NET_IPV6_ND
select NET_IPV6
select NET_IPV6_NBR_CACHE
select NET_ROUTE
help
See RFC 6550 and RFC 6551 for details. Enable this if required by
@ -177,6 +178,14 @@ config NET_RPL_DAO_TIMER
help
How many seconds to wait before sending DAO.
config NET_RPL_DAO_ACK
bool "Node expecting DAO ACK"
depends on NET_RPL
default n
help
Node expecting DAO ACK for DAO message. Enable if interested
in status of DAO message.
config NET_RPL_PREFERENCE
int "DAG preference field default value"
depends on NET_RPL

View file

@ -24,6 +24,8 @@
#define BUF_WAIT_TIME K_SECONDS(1)
static sys_slist_t handlers;
static inline enum net_verdict handle_echo_request(struct net_buf *buf)
{
/* Note that we send the same data buffers back and just swap
@ -161,24 +163,6 @@ int net_icmpv4_send_echo_request(struct net_if *iface,
return -EIO;
}
enum net_verdict net_icmpv4_input(struct net_buf *buf, uint16_t len,
uint8_t type, uint8_t code)
{
ARG_UNUSED(code);
ARG_UNUSED(len);
net_stats_update_icmp_recv();
switch (type) {
case NET_ICMPV4_ECHO_REQUEST:
return handle_echo_request(buf);
}
net_stats_update_icmp_drop();
return NET_DROP;
}
int net_icmpv4_send_error(struct net_buf *orig, uint8_t type, uint8_t code)
{
struct net_buf *buf, *frag;
@ -283,3 +267,42 @@ drop_no_buf:
return err;
}
void net_icmpv4_register_handler(struct net_icmpv4_handler *handler)
{
sys_slist_prepend(&handlers, &handler->node);
}
void net_icmpv4_unregister_handler(struct net_icmpv4_handler *handler)
{
sys_slist_find_and_remove(&handlers, &handler->node);
}
enum net_verdict net_icmpv4_input(struct net_buf *buf,
uint8_t type, uint8_t code)
{
struct net_icmpv4_handler *cb;
net_stats_update_icmp_recv();
SYS_SLIST_FOR_EACH_CONTAINER(&handlers, cb, node) {
if (cb->type == type && (cb->code == code || cb->code == 0)) {
return cb->handler(buf);
}
}
net_stats_update_icmp_drop();
return NET_DROP;
}
static struct net_icmpv4_handler echo_request_handler = {
.type = NET_ICMPV4_ECHO_REQUEST,
.code = 0,
.handler = handle_echo_request,
};
void net_icmpv4_init(void)
{
net_icmpv4_register_handler(&echo_request_handler);
}

View file

@ -34,6 +34,15 @@ struct net_icmpv4_echo_req {
((struct net_icmpv4_echo_req *)(net_nbuf_icmp_data(buf) + \
sizeof(struct net_icmp_hdr)))
typedef enum net_verdict (*icmpv4_callback_handler_t)(struct net_buf *buf);
struct net_icmpv4_handler {
sys_snode_t node;
uint8_t type;
uint8_t code;
icmpv4_callback_handler_t handler;
};
/**
* @brief Send ICMPv4 error message.
* @param buf Network buffer that this error is related to.
@ -60,7 +69,17 @@ int net_icmpv4_send_echo_request(struct net_if *iface,
uint16_t identifier,
uint16_t sequence);
enum net_verdict net_icmpv4_input(struct net_buf *buf, uint16_t len,
void net_icmpv4_register_handler(struct net_icmpv4_handler *handler);
void net_icmpv4_unregister_handler(struct net_icmpv4_handler *handler);
enum net_verdict net_icmpv4_input(struct net_buf *buf,
uint8_t type, uint8_t code);
#if defined(CONFIG_NET_IPV4)
void net_icmpv4_init(void);
#else
#define net_icmpv4_init(...)
#endif
#endif /* __ICMPV4_H */

View file

@ -58,33 +58,34 @@ NET_NBR_TABLE_INIT(NET_NBR_GLOBAL,
net_neighbor_pool,
net_neighbor_table_clear);
const char *net_nbr_state2str(enum net_nbr_state state)
const char *net_ipv6_nbr_state2str(enum net_ipv6_nbr_state state)
{
switch (state) {
case NET_NBR_INCOMPLETE:
case NET_IPV6_NBR_STATE_INCOMPLETE:
return "incomplete";
case NET_NBR_REACHABLE:
case NET_IPV6_NBR_STATE_REACHABLE:
return "reachable";
case NET_NBR_STALE:
case NET_IPV6_NBR_STATE_STALE:
return "stale";
case NET_NBR_DELAY:
case NET_IPV6_NBR_STATE_DELAY:
return "delay";
case NET_NBR_PROBE:
case NET_IPV6_NBR_STATE_PROBE:
return "probe";
}
return "<invalid state>";
}
static void nbr_set_state(struct net_nbr *nbr, enum net_nbr_state new_state)
static void ipv6_nbr_set_state(struct net_nbr *nbr,
enum net_ipv6_nbr_state new_state)
{
if (new_state == net_ipv6_nbr_data(nbr)->state) {
return;
}
NET_DBG("nbr %p %s -> %s", nbr,
net_nbr_state2str(net_ipv6_nbr_data(nbr)->state),
net_nbr_state2str(new_state));
net_ipv6_nbr_state2str(net_ipv6_nbr_data(nbr)->state),
net_ipv6_nbr_state2str(new_state));
net_ipv6_nbr_data(nbr)->state = new_state;
}
@ -245,7 +246,7 @@ struct net_nbr *net_ipv6_nbr_add(struct net_if *iface,
struct in6_addr *addr,
struct net_linkaddr *lladdr,
bool is_router,
enum net_nbr_state state)
enum net_ipv6_nbr_state state)
{
struct net_nbr *nbr = net_nbr_get(&net_neighbor.table);
@ -259,7 +260,7 @@ struct net_nbr *net_ipv6_nbr_add(struct net_if *iface,
}
net_ipaddr_copy(&net_ipv6_nbr_data(nbr)->addr, addr);
nbr_set_state(nbr, state);
ipv6_nbr_set_state(nbr, state);
net_ipv6_nbr_data(nbr)->is_router = is_router;
NET_DBG("[%d] nbr %p state %d router %d IPv6 %s ll %s",
@ -274,7 +275,7 @@ static inline struct net_nbr *nbr_add(struct net_buf *buf,
struct in6_addr *addr,
struct net_linkaddr *lladdr,
bool is_router,
enum net_nbr_state state)
enum net_ipv6_nbr_state state)
{
return net_ipv6_nbr_add(net_nbuf_iface(buf), addr, lladdr,
is_router, state);
@ -319,7 +320,7 @@ static void ns_reply_timeout(struct k_work *work)
static struct net_nbr *nbr_new(struct net_if *iface,
struct in6_addr *addr,
enum net_nbr_state state)
enum net_ipv6_nbr_state state)
{
struct net_nbr *nbr = net_nbr_get(&net_neighbor.table);
@ -331,7 +332,7 @@ static struct net_nbr *nbr_new(struct net_if *iface,
nbr->iface = iface;
net_ipaddr_copy(&net_ipv6_nbr_data(nbr)->addr, addr);
nbr_set_state(nbr, state);
ipv6_nbr_set_state(nbr, state);
net_ipv6_nbr_data(nbr)->pending = NULL;
#if defined(CONFIG_NET_IPV6_ND)
@ -550,12 +551,7 @@ static inline void dbg_update_neighbor_lladdr_raw(uint8_t *new_lladdr,
dbg_update_neighbor_lladdr(&lladdr, old_lladdr, addr);
}
#else
#define dbg_update_neighbor_lladdr(...)
#define dbg_update_neighbor_lladdr_raw(...)
#endif /* CONFIG_NET_DEBUG_IPV6 */
#if defined(CONFIG_NET_DEBUG_IPV6)
#define dbg_addr(action, pkt_str, src, dst) \
do { \
char out[NET_IPV6_ADDR_LEN]; \
@ -595,6 +591,8 @@ static inline void dbg_update_neighbor_lladdr_raw(uint8_t *new_lladdr,
#define dbg_addr_sent_tgt(pkt_str, src, dst, tgt) \
dbg_addr_with_tgt("Sent", pkt_str, src, dst, tgt)
#else
#define dbg_update_neighbor_lladdr(...)
#define dbg_update_neighbor_lladdr_raw(...)
#define dbg_addr(...)
#define dbg_addr_recv(...)
#define dbg_addr_sent(...)
@ -621,6 +619,14 @@ static struct net_buf *update_ll_reserve(struct net_buf *buf,
uint16_t reserve, room_len, copy_len, pos;
struct net_buf *orig_frag, *frag;
/* No need to do anything if we are forwarding the packet
* as we already know everything about the destination of
* the packet.
*/
if (net_nbuf_forwarding(buf)) {
return buf;
}
reserve = net_if_get_ll_reserve(net_nbuf_iface(buf), addr);
if (reserve == net_nbuf_ll_reserve(buf)) {
return buf;
@ -774,7 +780,8 @@ try_send:
nbr ? nbr->idx : NET_NBR_LLADDR_UNKNOWN,
net_nbuf_iface(buf),
net_sprint_ipv6_addr(nexthop),
net_nbr_state2str(net_ipv6_nbr_data(nbr)->state));
nbr ? net_ipv6_nbr_state2str(net_ipv6_nbr_data(nbr)->state) :
"-");
if (nbr && nbr->idx != NET_NBR_LLADDR_UNKNOWN) {
struct net_linkaddr_storage *lladdr;
@ -791,8 +798,8 @@ try_send:
* See RFC 4861 ch 7.3.3 for details.
*/
#if defined(CONFIG_NET_IPV6_ND)
if (net_ipv6_nbr_data(nbr)->state == NET_NBR_STALE) {
nbr_set_state(nbr, NET_NBR_DELAY);
if (net_ipv6_nbr_data(nbr)->state == NET_IPV6_NBR_STATE_STALE) {
ipv6_nbr_set_state(nbr, NET_IPV6_NBR_STATE_DELAY);
k_delayed_work_submit(
&net_ipv6_nbr_data(nbr)->reachable,
@ -931,7 +938,8 @@ static inline void handle_ns_neighbor(struct net_buf *buf,
nbr_print();
nbr = nbr_new(net_nbuf_iface(buf),
&NET_IPV6_BUF(buf)->src, NET_NBR_INCOMPLETE);
&NET_IPV6_BUF(buf)->src,
NET_IPV6_NBR_STATE_INCOMPLETE);
if (nbr) {
NET_DBG("Added %s to nbr cache",
net_sprint_ipv6_addr(&NET_IPV6_BUF(buf)->src));
@ -964,11 +972,12 @@ static inline void handle_ns_neighbor(struct net_buf *buf,
net_linkaddr_set(cached_lladdr, lladdr.addr,
lladdr.len);
nbr_set_state(nbr, NET_NBR_STALE);
ipv6_nbr_set_state(nbr, NET_IPV6_NBR_STATE_STALE);
} else {
if (net_ipv6_nbr_data(nbr)->state ==
NET_NBR_INCOMPLETE) {
nbr_set_state(nbr, NET_NBR_STALE);
NET_IPV6_NBR_STATE_INCOMPLETE) {
ipv6_nbr_set_state(nbr,
NET_IPV6_NBR_STATE_STALE);
}
}
}
@ -1235,7 +1244,7 @@ static void nd_reachable_timeout(struct k_work *work)
switch (data->state) {
case NET_NBR_INCOMPLETE:
case NET_IPV6_NBR_STATE_INCOMPLETE:
if (data->ns_count >= MAX_MULTICAST_SOLICIT) {
nbr_free(nbr);
} else {
@ -1249,21 +1258,21 @@ static void nd_reachable_timeout(struct k_work *work)
}
break;
case NET_NBR_REACHABLE:
data->state = NET_NBR_STALE;
case NET_IPV6_NBR_STATE_REACHABLE:
data->state = NET_IPV6_NBR_STATE_STALE;
NET_DBG("nbr %p moving %s state to STALE (%d)",
nbr, net_sprint_ipv6_addr(&data->addr), data->state);
break;
case NET_NBR_STALE:
case NET_IPV6_NBR_STATE_STALE:
NET_DBG("nbr %p removing stale address %s",
nbr, net_sprint_ipv6_addr(&data->addr));
nbr_free(nbr);
break;
case NET_NBR_DELAY:
data->state = NET_NBR_PROBE;
case NET_IPV6_NBR_STATE_DELAY:
data->state = NET_IPV6_NBR_STATE_PROBE;
data->ns_count = 0;
NET_DBG("nbr %p moving %s state to PROBE (%d)",
@ -1271,7 +1280,7 @@ static void nd_reachable_timeout(struct k_work *work)
/* Intentionally continuing to probe state */
case NET_NBR_PROBE:
case NET_IPV6_NBR_STATE_PROBE:
if (data->ns_count >= MAX_UNICAST_SOLICIT) {
struct net_if_router *router;
@ -1378,7 +1387,7 @@ static inline bool handle_na_neighbor(struct net_buf *buf,
}
/* Update the cached address if we do not yet known it */
if (net_ipv6_nbr_data(nbr)->state == NET_NBR_INCOMPLETE) {
if (net_ipv6_nbr_data(nbr)->state == NET_IPV6_NBR_STATE_INCOMPLETE) {
if (!tllao) {
return false;
}
@ -1395,7 +1404,7 @@ static inline bool handle_na_neighbor(struct net_buf *buf,
}
if (net_is_solicited(buf)) {
nbr_set_state(nbr, NET_NBR_REACHABLE);
ipv6_nbr_set_state(nbr, NET_IPV6_NBR_STATE_REACHABLE);
net_ipv6_nbr_data(nbr)->ns_count = 0;
/* We might have active timer from PROBE */
@ -1405,7 +1414,7 @@ static inline bool handle_na_neighbor(struct net_buf *buf,
net_ipv6_nbr_set_reachable_timer(net_nbuf_iface(buf),
nbr);
} else {
nbr_set_state(nbr, NET_NBR_STALE);
ipv6_nbr_set_state(nbr, NET_IPV6_NBR_STATE_STALE);
}
net_ipv6_nbr_data(nbr)->is_router = net_is_router(buf);
@ -1417,8 +1426,9 @@ static inline bool handle_na_neighbor(struct net_buf *buf,
* and we have a valid address in the cache.
*/
if (!net_is_override(buf) && lladdr_changed) {
if (net_ipv6_nbr_data(nbr)->state == NET_NBR_REACHABLE) {
nbr_set_state(nbr, NET_NBR_STALE);
if (net_ipv6_nbr_data(nbr)->state ==
NET_IPV6_NBR_STATE_REACHABLE) {
ipv6_nbr_set_state(nbr, NET_IPV6_NBR_STATE_STALE);
}
return false;
@ -1439,7 +1449,7 @@ static inline bool handle_na_neighbor(struct net_buf *buf,
}
if (net_is_solicited(buf)) {
nbr_set_state(nbr, NET_NBR_REACHABLE);
ipv6_nbr_set_state(nbr, NET_IPV6_NBR_STATE_REACHABLE);
/* We might have active timer from PROBE */
k_delayed_work_cancel(
@ -1449,7 +1459,8 @@ static inline bool handle_na_neighbor(struct net_buf *buf,
nbr);
} else {
if (lladdr_changed) {
nbr_set_state(nbr, NET_NBR_STALE);
ipv6_nbr_set_state(nbr,
NET_IPV6_NBR_STATE_STALE);
}
}
}
@ -1682,7 +1693,7 @@ int net_ipv6_send_ns(struct net_if *iface,
nbr = nbr_new(net_nbuf_iface(buf),
&NET_ICMPV6_NS_BUF(buf)->tgt,
NET_NBR_INCOMPLETE);
NET_IPV6_NBR_STATE_INCOMPLETE);
if (!nbr) {
NET_DBG("Could not create new neighbor %s",
net_sprint_ipv6_addr(
@ -1859,7 +1870,7 @@ static inline struct net_buf *handle_ra_neighbor(struct net_buf *buf,
nbr_print();
*nbr = nbr_add(buf, &NET_IPV6_BUF(buf)->src, &lladdr,
true, NET_NBR_STALE);
true, NET_IPV6_NBR_STATE_STALE);
if (!*nbr) {
NET_ERR("Could not add router neighbor %s [%s]",
net_sprint_ipv6_addr(&NET_IPV6_BUF(buf)->src),
@ -1883,11 +1894,12 @@ static inline struct net_buf *handle_ra_neighbor(struct net_buf *buf,
net_linkaddr_set(cached_lladdr, lladdr.addr,
lladdr.len);
nbr_set_state(*nbr, NET_NBR_STALE);
ipv6_nbr_set_state(*nbr, NET_IPV6_NBR_STATE_STALE);
} else {
if (net_ipv6_nbr_data(*nbr)->state ==
NET_NBR_INCOMPLETE) {
nbr_set_state(*nbr, NET_NBR_STALE);
NET_IPV6_NBR_STATE_INCOMPLETE) {
ipv6_nbr_set_state(*nbr,
NET_IPV6_NBR_STATE_STALE);
}
}
}

View file

@ -64,15 +64,15 @@
#define NET_IPV6_MLDv2_BLOCK_OLD_SOURCES 6
/* State of the neighbor */
enum net_nbr_state {
NET_NBR_INCOMPLETE,
NET_NBR_REACHABLE,
NET_NBR_STALE,
NET_NBR_DELAY,
NET_NBR_PROBE,
enum net_ipv6_nbr_state {
NET_IPV6_NBR_STATE_INCOMPLETE,
NET_IPV6_NBR_STATE_REACHABLE,
NET_IPV6_NBR_STATE_STALE,
NET_IPV6_NBR_STATE_DELAY,
NET_IPV6_NBR_STATE_PROBE,
};
const char *net_nbr_state2str(enum net_nbr_state state);
const char *net_ipv6_nbr_state2str(enum net_ipv6_nbr_state state);
/**
* @brief IPv6 neighbor information.
@ -91,7 +91,7 @@ struct net_ipv6_nbr_data {
struct k_delayed_work send_ns;
/** State of the neighbor discovery */
enum net_nbr_state state;
enum net_ipv6_nbr_state state;
/** Link metric for the neighbor */
uint16_t link_metric;
@ -289,7 +289,7 @@ struct net_nbr *net_ipv6_nbr_add(struct net_if *iface,
struct in6_addr *addr,
struct net_linkaddr *lladdr,
bool is_router,
enum net_nbr_state state);
enum net_ipv6_nbr_state state);
/**
* @brief Remove a neighbour from neighbor cache.
@ -332,7 +332,7 @@ static inline struct net_nbr *net_ipv6_nbr_add(struct net_if *iface,
struct in6_addr *addr,
struct net_linkaddr *lladdr,
bool is_router,
enum net_nbr_state state)
enum net_ipv6_nbr_state state)
{
return NULL;
}

View file

@ -29,19 +29,19 @@ config NET_DEBUG_L2_ETHERNET
help
Enables Ethernet L2 output debug messages
config NET_L2_OFFLOAD_IP
config NET_OFFLOAD
bool "Offload IP stack [EXPERIMENTAL]"
default n
help
Enables IP stack to be offload to a co-processor.
Enables TCP/IP stack to be offload to a co-processor.
config NET_DEBUG_L2_OFFLOAD
bool "Debug IP Offload L2 layer"
config NET_DEBUG_NET_OFFLOAD
bool "Debug Net Offload Layer"
default n
depends on NET_LOG
depends on NET_L2_OFFLOAD
depends on NET_OFFLOAD
help
Enables offload IP stack L2 output debug messages.
Enables offload TCP/IP stack output debug messages.
config NET_L2_BLUETOOTH
bool "Enable Bluetooth support"

View file

@ -144,7 +144,8 @@ static void ipsp_connected(struct bt_l2cap_chan *chan)
* A Bluetooth LE 6LN MUST NOT register its link-local address.
*/
net_ipv6_addr_create_iid(&in6, &ll);
net_ipv6_nbr_add(ctxt->iface, &in6, &ll, false, NET_NBR_REACHABLE);
net_ipv6_nbr_add(ctxt->iface, &in6, &ll, false,
NET_IPV6_NBR_STATE_REACHABLE);
/* Set iface up */
net_if_up(ctxt->iface);

View file

@ -23,7 +23,7 @@
#include <net/nbuf.h>
#include <net/net_ip.h>
#include <net/net_context.h>
#include <net/offload_ip.h>
#include <net/net_offload.h>
#include "connection.h"
#include "net_private.h"
@ -319,16 +319,16 @@ int net_context_get(sa_family_t family,
k_sem_give(&contexts_lock);
#if defined(CONFIG_NET_L2_OFFLOAD_IP)
#if defined(CONFIG_NET_OFFLOAD)
/* FIXME - Figure out a way to get the correct network interface
* as it is not known at this point yet.
*/
if (!ret && net_if_is_ip_offloaded(net_if_get_default())) {
ret = net_l2_offload_ip_get(net_if_get_default(),
family,
type,
ip_proto,
context);
ret = net_offload_get(net_if_get_default(),
family,
type,
ip_proto,
context);
if (ret < 0) {
(*context)->flags &= ~NET_CONTEXT_IN_USE;
*context = NULL;
@ -336,7 +336,7 @@ int net_context_get(sa_family_t family,
return ret;
}
#endif /* CONFIG_NET_L2_OFFLOAD_IP */
#endif /* CONFIG_NET_OFFLOAD */
return ret;
}
@ -405,14 +405,14 @@ int net_context_put(struct net_context *context)
return -EINVAL;
}
#if defined(CONFIG_NET_L2_OFFLOAD_IP)
#if defined(CONFIG_NET_OFFLOAD)
if (net_if_is_ip_offloaded(net_context_get_iface(context))) {
k_sem_take(&contexts_lock, K_FOREVER);
context->flags &= ~NET_CONTEXT_IN_USE;
return net_l2_offload_ip_put(
return net_offload_put(
net_context_get_iface(context), context);
}
#endif /* CONFIG_NET_L2_OFFLOAD_IP */
#endif /* CONFIG_NET_OFFLOAD */
context->connect_cb = NULL;
context->recv_cb = NULL;
@ -496,16 +496,16 @@ int net_context_bind(struct net_context *context, const struct sockaddr *addr,
return -EADDRNOTAVAIL;
}
#if defined(CONFIG_NET_L2_OFFLOAD_IP)
#if defined(CONFIG_NET_OFFLOAD)
if (net_if_is_ip_offloaded(iface)) {
net_context_set_iface(context, iface);
return net_l2_offload_ip_bind(iface,
context,
addr,
addrlen);
return net_offload_bind(iface,
context,
addr,
addrlen);
}
#endif /* CONFIG_NET_L2_OFFLOAD_IP */
#endif /* CONFIG_NET_OFFLOAD */
net_context_set_iface(context, iface);
@ -522,6 +522,9 @@ int net_context_bind(struct net_context *context, const struct sockaddr *addr,
ntohs(addr6->sin6_port));
return ret;
}
} else {
addr6->sin6_port =
net_sin6_ptr(&context->local)->sin6_port;
}
NET_DBG("Context %p binding to %s [%s]:%d iface %p",
@ -567,16 +570,16 @@ int net_context_bind(struct net_context *context, const struct sockaddr *addr,
return -EADDRNOTAVAIL;
}
#if defined(CONFIG_NET_L2_OFFLOAD_IP)
#if defined(CONFIG_NET_OFFLOAD)
if (net_if_is_ip_offloaded(iface)) {
net_context_set_iface(context, iface);
return net_l2_offload_ip_bind(iface,
context,
addr,
addrlen);
return net_offload_bind(iface,
context,
addr,
addrlen);
}
#endif /* CONFIG_NET_L2_OFFLOAD_IP */
#endif /* CONFIG_NET_OFFLOAD */
net_context_set_iface(context, iface);
@ -593,6 +596,9 @@ int net_context_bind(struct net_context *context, const struct sockaddr *addr,
ntohs(addr4->sin_port));
return ret;
}
} else {
addr4->sin_port =
net_sin_ptr(&context->local)->sin_port;
}
NET_DBG("Context %p binding to %s %s:%d iface %p",
@ -635,12 +641,12 @@ int net_context_listen(struct net_context *context, int backlog)
return -ENOENT;
}
#if defined(CONFIG_NET_L2_OFFLOAD_IP)
#if defined(CONFIG_NET_OFFLOAD)
if (net_if_is_ip_offloaded(net_context_get_iface(context))) {
return net_l2_offload_ip_listen(
return net_offload_listen(
net_context_get_iface(context), context, backlog);
}
#endif /* CONFIG_NET_L2_OFFLOAD_IP */
#endif /* CONFIG_NET_OFFLOAD */
#if defined(CONFIG_NET_TCP)
if (net_context_get_ip_proto(context) == IPPROTO_TCP) {
@ -827,7 +833,10 @@ NET_CONN_CB(tcp_established)
* LAST_ACK state
*/
context->tcp->fin_rcvd = 1;
net_tcp_change_state(context->tcp, NET_TCP_CLOSE_WAIT);
if (net_tcp_get_state(context->tcp) == NET_TCP_ESTABLISHED) {
net_tcp_change_state(context->tcp, NET_TCP_CLOSE_WAIT);
}
context->tcp->send_ack += 1;
@ -1005,9 +1014,9 @@ int net_context_connect(struct net_context *context,
return -EINVAL;
}
#if defined(CONFIG_NET_L2_OFFLOAD_IP)
#if defined(CONFIG_NET_OFFLOAD)
if (net_if_is_ip_offloaded(net_context_get_iface(context))) {
return net_l2_offload_ip_connect(
return net_offload_connect(
net_context_get_iface(context),
context,
addr,
@ -1016,7 +1025,7 @@ int net_context_connect(struct net_context *context,
timeout,
user_data);
}
#endif /* CONFIG_NET_L2_OFFLOAD_IP */
#endif /* CONFIG_NET_OFFLOAD */
if (net_context_get_state(context) == NET_CONTEXT_LISTENING) {
return -EOPNOTSUPP;
@ -1469,16 +1478,16 @@ int net_context_accept(struct net_context *context,
return -ENOENT;
}
#if defined(CONFIG_NET_L2_OFFLOAD_IP)
#if defined(CONFIG_NET_OFFLOAD)
if (net_if_is_ip_offloaded(net_context_get_iface(context))) {
return net_l2_offload_ip_accept(
return net_offload_accept(
net_context_get_iface(context),
context,
cb,
timeout,
user_data);
}
#endif /* CONFIG_NET_L2_OFFLOAD_IP */
#endif /* CONFIG_NET_OFFLOAD */
if ((net_context_get_state(context) != NET_CONTEXT_LISTENING) &&
(net_context_get_type(context) != SOCK_STREAM)) {
@ -1656,14 +1665,14 @@ static int sendto(struct net_buf *buf,
return -EDESTADDRREQ;
}
#if defined(CONFIG_NET_L2_OFFLOAD_IP)
#if defined(CONFIG_NET_OFFLOAD)
if (net_if_is_ip_offloaded(net_nbuf_iface(buf))) {
return net_l2_offload_ip_sendto(
return net_offload_sendto(
net_nbuf_iface(buf),
buf, dst_addr, addrlen,
cb, timeout, token, user_data);
}
#endif /* CONFIG_NET_L2_OFFLOAD_IP */
#endif /* CONFIG_NET_OFFLOAD */
#if defined(CONFIG_NET_IPV6)
if (net_nbuf_family(buf) == AF_INET6) {
@ -1733,14 +1742,14 @@ int net_context_send(struct net_buf *buf,
NET_ASSERT(PART_OF_ARRAY(contexts, context));
#if defined(CONFIG_NET_L2_OFFLOAD_IP)
#if defined(CONFIG_NET_OFFLOAD)
if (net_if_is_ip_offloaded(net_nbuf_iface(buf))) {
return net_l2_offload_ip_send(
return net_offload_send(
net_nbuf_iface(buf),
buf, cb, timeout,
token, user_data);
}
#endif /* CONFIG_NET_L2_OFFLOAD_IP */
#endif /* CONFIG_NET_OFFLOAD */
if (!(context->flags & NET_CONTEXT_REMOTE_ADDR_SET) ||
!net_sin(&context->remote)->sin_port) {
@ -1939,13 +1948,13 @@ int net_context_recv(struct net_context *context,
return -ENOENT;
}
#if defined(CONFIG_NET_L2_OFFLOAD_IP)
#if defined(CONFIG_NET_OFFLOAD)
if (net_if_is_ip_offloaded(net_context_get_iface(context))) {
return net_l2_offload_ip_recv(
return net_offload_recv(
net_context_get_iface(context),
context, cb, timeout, user_data);
}
#endif /* CONFIG_NET_L2_OFFLOAD_IP */
#endif /* CONFIG_NET_OFFLOAD */
#if defined(CONFIG_NET_UDP)
if (net_context_get_ip_proto(context) == IPPROTO_UDP) {

View file

@ -28,6 +28,7 @@
#include <net/arp.h>
#include <net/nbuf.h>
#include <net/net_core.h>
#include <net/dns_resolve.h>
#include "net_private.h"
#include "net_shell.h"
@ -35,9 +36,7 @@
#include "icmpv6.h"
#include "ipv6.h"
#if defined(CONFIG_NET_IPV4)
#include "icmpv4.h"
#endif
#if defined(CONFIG_NET_DHCPV4)
#include "dhcpv4.h"
@ -258,7 +257,29 @@ static inline enum net_verdict process_ipv6_pkt(struct net_buf *buf)
!net_is_my_ipv6_maddr(&hdr->dst) &&
!net_is_ipv6_addr_mcast(&hdr->dst) &&
!net_is_ipv6_addr_loopback(&hdr->dst)) {
NET_DBG("IPv6 packet in buf %p not for me", buf);
#if defined(CONFIG_NET_ROUTE)
struct net_route_entry *route;
struct in6_addr *nexthop;
/* Check if the packet can be routed */
if (net_route_get_info(&hdr->dst, &route, &nexthop)) {
int ret;
ret = net_route_packet(buf, route, nexthop);
if (ret < 0) {
NET_DBG("Cannot re-route buf %p via %s (%d)",
buf, net_sprint_ipv6_addr(nexthop),
ret);
} else {
return NET_OK;
}
} else
#endif /* CONFIG_NET_ROUTE */
{
NET_DBG("IPv6 packet in buf %p not for me", buf);
}
net_stats_update_ipv6_drop();
goto drop;
}
@ -392,12 +413,11 @@ static inline enum net_verdict process_icmpv4_pkt(struct net_buf *buf,
struct net_ipv4_hdr *ipv4)
{
struct net_icmp_hdr *hdr = NET_ICMP_BUF(buf);
uint16_t len = (ipv4->len[0] << 8) + ipv4->len[1];
NET_DBG("ICMPv4 packet received length %d type %d code %d",
len, hdr->type, hdr->code);
NET_DBG("ICMPv4 packet received type %d code %d",
hdr->type, hdr->code);
return net_icmpv4_input(buf, len, hdr->type, hdr->code);
return net_icmpv4_input(buf, hdr->type, hdr->code);
}
#endif /* CONFIG_NET_IPV4 */
@ -735,6 +755,7 @@ int net_recv_data(struct net_if *iface, struct net_buf *buf)
static inline void l3_init(void)
{
net_icmpv4_init();
net_icmpv6_init();
net_ipv6_init();
@ -746,6 +767,8 @@ static inline void l3_init(void)
net_route_init();
dns_init_resolver();
NET_DBG("Network L3 init done");
}

View file

@ -443,7 +443,11 @@ void net_if_start_dad(struct net_if *iface)
}
}
#else
#define net_if_ipv6_start_dad(...)
static inline void net_if_ipv6_start_dad(struct net_if *iface,
struct net_if_addr *ifaddr)
{
ifaddr->addr_state = NET_ADDR_PREFERRED;
}
#endif /* CONFIG_NET_IPV6_DAD */
#if defined(CONFIG_NET_IPV6_ND)
@ -1043,6 +1047,8 @@ struct net_if_router *net_if_ipv6_router_add(struct net_if *iface,
i, iface, net_sprint_ipv6_addr(addr), lifetime,
routers[i].is_default);
net_mgmt_event_notify(NET_EVENT_IPV6_ROUTER_ADD, iface);
return &routers[i];
}
@ -1066,6 +1072,9 @@ bool net_if_ipv6_router_rm(struct net_if_router *router)
routers[i].is_used = false;
net_mgmt_event_notify(NET_EVENT_IPV6_ROUTER_DEL,
routers[i].iface);
NET_DBG("[%d] router %s removed",
i, net_sprint_ipv6_addr(&routers[i].address.in6_addr));

View file

@ -15,6 +15,7 @@
#include <shell/shell.h>
#include <net/net_if.h>
#include <net/dns_resolve.h>
#include <misc/printk.h>
#include "route.h"
@ -568,6 +569,198 @@ static int shell_cmd_conn(int argc, char *argv[])
return 0;
}
#if defined(CONFIG_DNS_RESOLVER)
static void dns_result_cb(enum dns_resolve_status status,
struct dns_addrinfo *info,
void *user_data)
{
bool *first = user_data;
if (status == DNS_EAI_CANCELED) {
printk("\nTimeout while resolving name.\n");
*first = false;
return;
}
if (status == DNS_EAI_INPROGRESS && info) {
char addr[NET_IPV6_ADDR_LEN];
if (*first) {
printk("\n");
*first = false;
}
if (info->ai_family == AF_INET) {
net_addr_ntop(AF_INET,
&net_sin(&info->ai_addr)->sin_addr,
addr, NET_IPV4_ADDR_LEN);
} else if (info->ai_family == AF_INET6) {
net_addr_ntop(AF_INET6,
&net_sin6(&info->ai_addr)->sin6_addr,
addr, NET_IPV6_ADDR_LEN);
} else {
strncpy(addr, "Invalid protocol family",
sizeof(addr));
}
printk("\t%s\n", addr);
return;
}
if (status == DNS_EAI_ALLDONE) {
printk("All results received\n");
*first = false;
return;
}
if (status == DNS_EAI_FAIL) {
printk("No such name found.\n");
*first = false;
return;
}
printk("Unhandled status %d received\n", status);
}
static void print_dns_info(struct dns_resolve_context *ctx)
{
int i;
printk("DNS servers:\n");
for (i = 0; i < CONFIG_DNS_RESOLVER_MAX_SERVERS; i++) {
if (ctx->servers[i].dns_server.family == AF_INET) {
printk("\t%s:%u\n",
net_sprint_ipv4_addr(
&net_sin(&ctx->servers[i].dns_server)->
sin_addr),
ntohs(net_sin(&ctx->servers[i].
dns_server)->sin_port));
} else if (ctx->servers[i].dns_server.family == AF_INET6) {
printk("\t[%s]:%u\n",
net_sprint_ipv6_addr(
&net_sin6(&ctx->servers[i].dns_server)->
sin6_addr),
ntohs(net_sin6(&ctx->servers[i].
dns_server)->sin6_port));
}
}
printk("Pending queries:\n");
for (i = 0; i < CONFIG_DNS_NUM_CONCUR_QUERIES; i++) {
int32_t remaining;
if (!ctx->queries[i].cb) {
continue;
}
remaining =
k_delayed_work_remaining_get(&ctx->queries[i].timer);
if (ctx->queries[i].query_type == DNS_QUERY_TYPE_A) {
printk("\tIPv4[%u]: %s remaining %d\n",
ctx->queries[i].id,
ctx->queries[i].query,
remaining);
} else if (ctx->queries[i].query_type == DNS_QUERY_TYPE_AAAA) {
printk("\tIPv6[%u]: %s remaining %d\n",
ctx->queries[i].id,
ctx->queries[i].query,
remaining);
}
}
}
#endif
static int shell_cmd_dns(int argc, char *argv[])
{
#if defined(CONFIG_DNS_RESOLVER)
#define DNS_TIMEOUT 2000 /* ms */
struct dns_resolve_context *ctx;
enum dns_query_type qtype = DNS_QUERY_TYPE_A;
char *host, *type = NULL;
bool first = true;
int arg = 1;
int ret, i;
if (strcmp(argv[0], "dns")) {
arg++;
}
if (!argv[arg]) {
/* DNS status */
ctx = dns_resolve_get_default();
if (!ctx) {
printk("No default DNS context found.\n");
return 0;
}
print_dns_info(ctx);
return 0;
}
if (strcmp(argv[arg], "cancel") == 0) {
ctx = dns_resolve_get_default();
if (!ctx) {
printk("No default DNS context found.\n");
return 0;
}
for (ret = 0, i = 0; i < CONFIG_DNS_NUM_CONCUR_QUERIES; i++) {
if (!ctx->queries[i].cb) {
continue;
}
if (!dns_resolve_cancel(ctx, ctx->queries[i].id)) {
ret++;
}
}
if (ret) {
printk("Cancelled %d pending requests.\n", ret);
} else {
printk("No pending DNS requests.\n");
}
return 0;
}
host = argv[arg++];
if (argv[arg]) {
type = argv[arg];
}
if (type) {
if (strcmp(type, "A") == 0) {
qtype = DNS_QUERY_TYPE_A;
printk("IPv4 address type\n");
} else if (strcmp(type, "AAAA") == 0) {
qtype = DNS_QUERY_TYPE_AAAA;
printk("IPv6 address type\n");
} else {
printk("Unknown query type, specify either "
"A or AAAA\n");
return 0;
}
}
ret = dns_get_addr_info(host, qtype, NULL, dns_result_cb, &first,
DNS_TIMEOUT);
if (ret < 0) {
printk("Cannot resolve '%s' (%d)\n", host, ret);
} else {
printk("Query for '%s' sent.\n", host);
}
#else
printk("DNS resolver not supported.\n");
#endif
return 0;
}
static int shell_cmd_iface(int argc, char *argv[])
{
ARG_UNUSED(argc);
@ -721,7 +914,7 @@ static void nbr_cb(struct net_nbr *nbr, void *user_data)
net_ipv6_nbr_data(nbr)->is_router,
net_ipv6_nbr_data(nbr)->link_metric,
nbr->iface,
net_nbr_state2str(net_ipv6_nbr_data(nbr)->state),
net_ipv6_nbr_state2str(net_ipv6_nbr_data(nbr)->state),
k_delayed_work_remaining_get(
&net_ipv6_nbr_data(nbr)->reachable),
nbr->idx == NET_NBR_LLADDR_UNKNOWN ? "?" :
@ -783,14 +976,131 @@ static int shell_cmd_nbr(int argc, char *argv[])
return 0;
}
#if defined(CONFIG_NET_IPV6) || defined(CONFIG_NET_IPV4)
K_SEM_DEFINE(ping_timeout, 0, 1);
#if defined(CONFIG_NET_IPV6)
static enum net_verdict _handle_ipv6_echo_reply(struct net_buf *buf);
static struct net_icmpv6_handler ping6_handler = {
.type = NET_ICMPV6_ECHO_REPLY,
.code = 0,
.handler = _handle_ipv6_echo_reply,
};
static inline void _remove_ipv6_ping_handler(void)
{
net_icmpv6_unregister_handler(&ping6_handler);
}
static enum net_verdict _handle_ipv6_echo_reply(struct net_buf *buf)
{
char addr[NET_IPV6_ADDR_LEN];
snprintk(addr, sizeof(addr), "%s",
net_sprint_ipv6_addr(&NET_IPV6_BUF(buf)->dst));
printk("Received echo reply from %s to %s\n",
net_sprint_ipv6_addr(&NET_IPV6_BUF(buf)->src), addr);
k_sem_give(&ping_timeout);
_remove_ipv6_ping_handler();
return NET_OK;
}
static int _ping_ipv6(char *host)
{
struct in6_addr ipv6_target;
int ret;
if (net_addr_pton(AF_INET6, host, &ipv6_target) < 0) {
return -EINVAL;
}
net_icmpv6_register_handler(&ping6_handler);
ret = net_icmpv6_send_echo_request(net_if_get_default(),
&ipv6_target,
sys_rand32_get(),
sys_rand32_get());
if (ret) {
_remove_ipv6_ping_handler();
} else {
printk("Sent a ping to %s\n", host);
}
return ret;
}
#else
#define _ping_ipv6(...) -EINVAL
#define _remove_ipv6_ping_handler()
#endif /* CONFIG_NET_IPV6 */
#if defined(CONFIG_NET_IPV4)
static enum net_verdict _handle_ipv4_echo_reply(struct net_buf *buf);
static struct net_icmpv4_handler ping4_handler = {
.type = NET_ICMPV4_ECHO_REPLY,
.code = 0,
.handler = _handle_ipv4_echo_reply,
};
static inline void _remove_ipv4_ping_handler(void)
{
net_icmpv4_unregister_handler(&ping4_handler);
}
static enum net_verdict _handle_ipv4_echo_reply(struct net_buf *buf)
{
char addr[NET_IPV4_ADDR_LEN];
snprintk(addr, sizeof(addr), "%s",
net_sprint_ipv4_addr(&NET_IPV4_BUF(buf)->dst));
printk("Received echo reply from %s to %s\n",
net_sprint_ipv4_addr(&NET_IPV4_BUF(buf)->src), addr);
k_sem_give(&ping_timeout);
_remove_ipv4_ping_handler();
return NET_OK;
}
static int _ping_ipv4(char *host)
{
struct in_addr ipv4_target;
int ret;
if (net_addr_pton(AF_INET, host, &ipv4_target) < 0) {
return -EINVAL;
}
net_icmpv4_register_handler(&ping4_handler);
ret = net_icmpv4_send_echo_request(net_if_get_default(),
&ipv4_target,
sys_rand32_get(),
sys_rand32_get());
if (ret) {
_remove_ipv4_ping_handler();
} else {
printk("Sent a ping to %s\n", host);
}
return ret;
}
#else
#define _ping_ipv4(...) -EINVAL
#define _remove_ipv4_ping_handler()
#endif /* CONFIG_NET_IPV4 */
#endif /* CONFIG_NET_IPV6 || CONFIG_NET_IPV4 */
static int shell_cmd_ping(int argc, char *argv[])
{
#if defined(CONFIG_NET_IPV6)
struct in6_addr ipv6_target;
#endif
#if defined(CONFIG_NET_IPV4)
struct in_addr ipv4_target;
#endif
char *host;
int ret;
@ -802,66 +1112,32 @@ static int shell_cmd_ping(int argc, char *argv[])
host = argv[2];
}
#if defined(CONFIG_NET_IPV6) && !defined(CONFIG_NET_IPV4)
ret = net_addr_pton(AF_INET6, host, &ipv6_target);
if (ret < 0) {
printk("Invalid IPv6 address\n");
return 0;
}
ret = net_icmpv6_send_echo_request(net_if_get_default(),
&ipv6_target,
sys_rand32_get(),
sys_rand32_get());
if (ret < 0) {
ret = _ping_ipv6(host);
if (!ret) {
goto wait_reply;
} else if (ret == -EIO) {
printk("Cannot send IPv6 ping\n");
}
#endif
#if defined(CONFIG_NET_IPV4) && !defined(CONFIG_NET_IPV6)
ret = net_addr_pton(AF_INET, host, &ipv4_target);
if (ret < 0) {
printk("Invalid IPv4 address\n");
return 0;
}
ret = net_icmpv4_send_echo_request(net_if_get_default(),
&ipv4_target,
sys_rand32_get(),
sys_rand32_get());
if (ret < 0) {
printk("Cannot send IPv4 ping\n");
}
#endif
#if defined(CONFIG_NET_IPV6) && defined(CONFIG_NET_IPV4)
ret = net_addr_pton(AF_INET6, host, &ipv6_target);
if (ret < 0) {
ret = net_addr_pton(AF_INET, host, &ipv4_target);
if (ret < 0) {
printk("Invalid IP address\n");
return 0;
}
ret = net_icmpv4_send_echo_request(net_if_get_default(),
&ipv4_target,
sys_rand32_get(),
sys_rand32_get());
if (ret < 0) {
ret = _ping_ipv4(host);
if (ret) {
if (ret == -EIO) {
printk("Cannot send IPv4 ping\n");
} else if (ret == -EINVAL) {
printk("Invalid IP address\n");
}
return 0;
} else {
ret = net_icmpv6_send_echo_request(net_if_get_default(),
&ipv6_target,
sys_rand32_get(),
sys_rand32_get());
if (ret < 0) {
printk("Cannot send IPv6 ping\n");
}
}
#endif
wait_reply:
ret = k_sem_take(&ping_timeout, K_SECONDS(2));
if (ret == -EAGAIN) {
printk("Ping timeout\n");
_remove_ipv6_ping_handler();
_remove_ipv4_ping_handler();
}
return 0;
}
@ -950,6 +1226,288 @@ static int shell_cmd_stats(int argc, char *argv[])
return 0;
}
#if defined(CONFIG_NET_TCP)
static struct net_context *tcp_ctx;
#define TCP_CONNECT_TIMEOUT K_SECONDS(5) /* ms */
#define TCP_TIMEOUT K_SECONDS(2) /* ms */
static void tcp_connected(struct net_context *context,
int status,
void *user_data)
{
if (status < 0) {
printk("TCP connection failed (%d)\n", status);
net_context_put(context);
tcp_ctx = NULL;
} else {
printk("TCP connected\n");
}
}
#if defined(CONFIG_NET_IPV6)
static void get_my_ipv6_addr(struct net_if *iface,
struct sockaddr *myaddr)
{
const struct in6_addr *my6addr;
my6addr = net_if_ipv6_select_src_addr(net_if_get_default(),
&net_sin6(myaddr)->sin6_addr);
memcpy(&net_sin6(myaddr)->sin6_addr, my6addr, sizeof(struct in6_addr));
net_sin6(myaddr)->sin6_port = 0; /* let the IP stack to select */
}
#endif
#if defined(CONFIG_NET_IPV4)
static void get_my_ipv4_addr(struct net_if *iface,
struct sockaddr *myaddr)
{
/* Just take the first IPv4 address of an interface. */
memcpy(&net_sin(myaddr)->sin_addr,
&iface->ipv4.unicast[0].address.in_addr,
sizeof(struct in_addr));
net_sin(myaddr)->sin_port = 0; /* let the IP stack to select */
}
#endif
static void print_connect_info(int family,
struct sockaddr *myaddr,
struct sockaddr *addr)
{
switch (family) {
case AF_INET:
#if defined(CONFIG_NET_IPV4)
printk("Connecting from %s:%u ",
net_sprint_ipv4_addr(&net_sin(myaddr)->sin_addr),
ntohs(net_sin(myaddr)->sin_port));
printk("to %s:%u\n",
net_sprint_ipv4_addr(&net_sin(addr)->sin_addr),
ntohs(net_sin(addr)->sin_port));
#else
printk("IPv4 not supported\n");
#endif
break;
case AF_INET6:
#if defined(CONFIG_NET_IPV6)
printk("Connecting from [%s]:%u ",
net_sprint_ipv6_addr(&net_sin6(myaddr)->sin6_addr),
ntohs(net_sin6(myaddr)->sin6_port));
printk("to [%s]:%u\n",
net_sprint_ipv6_addr(&net_sin6(addr)->sin6_addr),
ntohs(net_sin6(addr)->sin6_port));
#else
printk("IPv6 not supported\n");
#endif
break;
default:
printk("Unknown protocol family (%d)\n", family);
break;
}
}
static int tcp_connect(char *host, uint16_t port, struct net_context **ctx)
{
struct sockaddr addr;
struct sockaddr myaddr;
int addrlen;
int family;
int ret;
#if defined(CONFIG_NET_IPV6) && !defined(CONFIG_NET_IPV4)
ret = net_addr_pton(AF_INET6, host, &net_sin6(&addr)->sin6_addr);
if (ret < 0) {
printk("Invalid IPv6 address\n");
return 0;
}
net_sin6(&addr)->sin6_port = htons(port);
addrlen = sizeof(struct sockaddr_in6);
get_my_ipv6_addr(net_if_get_default(), &myaddr);
family = addr.family = myaddr.family = AF_INET6;
#endif
#if defined(CONFIG_NET_IPV4) && !defined(CONFIG_NET_IPV6)
ret = net_addr_pton(AF_INET, host, &net_sin(&addr)->sin_addr);
if (ret < 0) {
printk("Invalid IPv4 address\n");
return 0;
}
get_my_ipv4_addr(net_if_get_default(), &myaddr);
net_sin(&addr)->sin_port = htons(port);
addrlen = sizeof(struct sockaddr_in);
family = addr.family = myaddr.family = AF_INET;
#endif
#if defined(CONFIG_NET_IPV6) && defined(CONFIG_NET_IPV4)
ret = net_addr_pton(AF_INET6, host, &net_sin6(&addr)->sin6_addr);
if (ret < 0) {
ret = net_addr_pton(AF_INET, host, &net_sin(&addr)->sin_addr);
if (ret < 0) {
printk("Invalid IP address\n");
return 0;
}
net_sin(&addr)->sin_port = htons(port);
addrlen = sizeof(struct sockaddr_in);
get_my_ipv4_addr(net_if_get_default(), &myaddr);
family = addr.family = myaddr.family = AF_INET;
} else {
net_sin6(&addr)->sin6_port = htons(port);
addrlen = sizeof(struct sockaddr_in6);
get_my_ipv6_addr(net_if_get_default(), &myaddr);
family = addr.family = myaddr.family = AF_INET6;
}
#endif
print_connect_info(family, &myaddr, &addr);
ret = net_context_get(family, SOCK_STREAM, IPPROTO_TCP, ctx);
if (ret < 0) {
printk("Cannot get TCP context (%d)\n", ret);
return ret;
}
ret = net_context_bind(*ctx, &myaddr, addrlen);
if (ret < 0) {
printk("Cannot bind TCP (%d)\n", ret);
return ret;
}
return net_context_connect(*ctx, &addr, addrlen, tcp_connected,
K_NO_WAIT, NULL);
}
static void tcp_sent_cb(struct net_context *context,
int status,
void *token,
void *user_data)
{
printk("Message sent\n");
}
#endif
static int shell_cmd_tcp(int argc, char *argv[])
{
#if defined(CONFIG_NET_TCP)
int arg = 1;
int ret;
if (strcmp(argv[0], "tcp")) {
arg++;
}
if (argv[arg]) {
if (!strcmp(argv[arg], "connect")) {
/* tcp connect <ip> port */
char *ip;
uint16_t port;
if (tcp_ctx && net_context_is_used(tcp_ctx)) {
printk("Already connected\n");
return 0;
}
if (!argv[++arg]) {
printk("Peer IP address missing.\n");
return 0;
}
ip = argv[arg];
if (!argv[++arg]) {
printk("Peer port missing.\n");
return 0;
}
port = strtol(argv[arg], NULL, 10);
return tcp_connect(ip, port, &tcp_ctx);
}
if (!strcmp(argv[arg], "send")) {
/* tcp send <data> */
struct net_buf *buf;
if (!tcp_ctx || !net_context_is_used(tcp_ctx)) {
printk("Not connected\n");
return 0;
}
if (!argv[++arg]) {
printk("No data to send.\n");
return 0;
}
buf = net_nbuf_get_tx(tcp_ctx, TCP_TIMEOUT);
if (!buf) {
printk("Out of bufs, msg cannot be sent.\n");
return 0;
}
ret = net_nbuf_append(buf, strlen(argv[arg]),
argv[arg], TCP_TIMEOUT);
if (!ret) {
printk("Cannot build msg (out of bufs)\n");
net_nbuf_unref(buf);
return 0;
}
ret = net_context_send(buf, tcp_sent_cb, TCP_TIMEOUT,
NULL, NULL);
if (ret < 0) {
printk("Cannot send msg (%d)\n", ret);
net_nbuf_unref(buf);
return 0;
}
return 0;
}
if (!strcmp(argv[arg], "close")) {
/* tcp close */
if (!tcp_ctx || !net_context_is_used(tcp_ctx)) {
printk("Not connected\n");
return 0;
}
ret = net_context_put(tcp_ctx);
if (ret < 0) {
printk("Cannot close the connection (%d)\n",
ret);
return 0;
}
printk("Connection closed.\n");
tcp_ctx = NULL;
return 0;
}
printk("Unknown command '%s'\n", argv[arg]);
goto usage;
} else {
printk("Invalid command.\n");
usage:
printk("Usage:\n");
printk("\ttcp connect <ipaddr> port\n");
printk("\ttcp send <data>\n");
printk("\ttcp close\n");
}
#else
printk("TCP not enabled.\n");
#endif /* CONFIG_NET_TCP */
return 0;
}
static int shell_cmd_help(int argc, char *argv[])
{
ARG_UNUSED(argc);
@ -958,6 +1516,10 @@ static int shell_cmd_help(int argc, char *argv[])
/* Keep the commands in alphabetical order */
printk("net allocs\n\tPrint network buffer allocations\n");
printk("net conn\n\tPrint information about network connections\n");
printk("net dns\n\tShow how DNS is configured\n");
printk("net dns cancel\n\tCancel all pending requests\n");
printk("net dns <hostname> [A or AAAA]\n\tQuery IPv4 address (default)"
" or IPv6 address for a host name\n");
printk("net iface\n\tPrint information about network interfaces\n");
printk("net mem\n\tPrint network buffer information\n");
printk("net nbr\n\tPrint neighbor information\n");
@ -966,6 +1528,9 @@ static int shell_cmd_help(int argc, char *argv[])
printk("net route\n\tShow network routes\n");
printk("net stacks\n\tShow network stacks information\n");
printk("net stats\n\tShow network statistics\n");
printk("net tcp connect <ip> port\n\tConnect to TCP peer\n");
printk("net tcp send <data>\n\tSend data to peer using TCP\n");
printk("net tcp close\n\tClose TCP connection\n");
return 0;
}
@ -973,6 +1538,7 @@ static struct shell_cmd net_commands[] = {
/* Keep the commands in alphabetical order */
{ "allocs", shell_cmd_allocs, NULL },
{ "conn", shell_cmd_conn, NULL },
{ "dns", shell_cmd_dns, NULL },
{ "help", shell_cmd_help, NULL },
{ "iface", shell_cmd_iface, NULL },
{ "mem", shell_cmd_mem, NULL },
@ -981,6 +1547,7 @@ static struct shell_cmd net_commands[] = {
{ "route", shell_cmd_route, NULL },
{ "stacks", shell_cmd_stacks, NULL },
{ "stats", shell_cmd_stats, NULL },
{ "tcp", shell_cmd_tcp, NULL },
{ NULL, NULL, NULL }
};

View file

@ -671,6 +671,77 @@ net_route_mcast_lookup(struct in6_addr *group)
}
#endif /* CONFIG_NET_ROUTE_MCAST */
bool net_route_get_info(struct in6_addr *dst,
struct net_route_entry **route,
struct in6_addr **nexthop)
{
struct net_if_router *router;
*route = net_route_lookup(NULL, dst);
if (*route) {
*nexthop = net_route_get_nexthop(*route);
if (!*nexthop) {
return false;
}
return true;
} else {
/* No specific route to this host, use the default
* route instead.
*/
router = net_if_ipv6_router_find_default(NULL, dst);
if (!router) {
return false;
}
*nexthop = &router->address.in6_addr;
return true;
}
return false;
}
int net_route_packet(struct net_buf *buf, struct net_route_entry *route,
struct in6_addr *nexthop)
{
struct net_linkaddr_storage *lladdr;
struct net_nbr *nbr;
if (route) {
net_nbuf_set_iface(buf, route->iface);
}
nbr = net_ipv6_nbr_lookup(net_nbuf_iface(buf), nexthop);
if (!nbr) {
NET_DBG("Cannot find %s neighbor.",
net_sprint_ipv6_addr(nexthop));
return -ENOENT;
}
lladdr = net_nbr_get_lladdr(nbr->idx);
if (!lladdr) {
NET_DBG("Cannot find %s neighbor link layer address.",
net_sprint_ipv6_addr(nexthop));
return -ESRCH;
}
net_nbuf_set_forwarding(buf, true);
/* Set the destination and source ll address in the packet.
* We set the destination address to be the nexthop recipient.
*/
net_nbuf_ll_src(buf)->addr = net_nbuf_ll_if(buf)->addr;
net_nbuf_ll_src(buf)->type = net_nbuf_ll_if(buf)->type;
net_nbuf_ll_src(buf)->len = net_nbuf_ll_if(buf)->len;
net_nbuf_ll_dst(buf)->addr = lladdr->addr;
net_nbuf_ll_dst(buf)->type = lladdr->type;
net_nbuf_ll_dst(buf)->len = lladdr->len;
return net_send_data(buf);
}
void net_route_init(void)
{
NET_DBG("Allocated %d routing entries (%zu bytes)",

View file

@ -233,6 +233,31 @@ net_route_mcast_lookup(struct in6_addr *group);
#endif /* CONFIG_NET_ROUTE_MCAST */
/**
* @brief Return a route to destination via some intermediate host.
*
* @param dst Destination IPv6 address
* @param route Route entry to destination is returned.
* @param nexthop Next hop neighbor IPv6 address is returned.
*
* @return True if there is a route to the destination, False otherwise
*/
bool net_route_get_info(struct in6_addr *dst,
struct net_route_entry **route,
struct in6_addr **nexthop);
/**
* @brief Send the network packet to network via some intermediate host.
*
* @param buf Network buffer to send.
* @param route Route entry to destination.
* @param nexthop Next hop neighbor IPv6 address.
*
* @return 0 if there was no error, <0 if the packet could not be sent.
*/
int net_route_packet(struct net_buf *buf, struct net_route_entry *route,
struct in6_addr *nexthop);
#else /* CONFIG_NET_ROUTE */
#define net_route_init(...)
#endif /* CONFIG_NET_ROUTE */

View file

@ -2700,7 +2700,7 @@ static enum net_verdict handle_dio(struct net_buf *buf)
&NET_IPV6_BUF(buf)->src,
net_nbuf_ll_src(buf),
0,
NET_NBR_REACHABLE);
NET_IPV6_NBR_STATE_REACHABLE);
if (!nbr) {
NET_DBG("Cannot add neighbor by DIO");
goto out;
@ -2719,7 +2719,7 @@ static enum net_verdict handle_dio(struct net_buf *buf)
frag = net_nbuf_read_u8(frag, pos, &pos, &dio.version);
frag = net_nbuf_read_be16(frag, pos, &pos, &dio.rank);
NET_DBG("Incoming DIO len %d id %d ver %d rank %d",
NET_DBG("Incoming DIO len %zu id %d ver %d rank %d",
net_buf_frags_len(buf) - offset,
dio.instance_id, dio.version, dio.rank);
@ -3080,8 +3080,13 @@ static inline int dao_forward(struct net_if *iface,
net_ipaddr_copy(&NET_IPV6_BUF(buf)->dst, dst);
net_nbuf_set_ip_hdr_len(buf, sizeof(struct net_ipv6_hdr));
net_nbuf_set_family(buf, AF_INET6);
net_nbuf_set_iface(buf, iface);
NET_ICMP_BUF(buf)->chksum = 0;
NET_ICMP_BUF(buf)->chksum = ~net_calc_chksum_icmpv6(buf);
ret = net_send_data(buf);
if (ret >= 0) {
net_stats_update_icmp_sent();
@ -3093,13 +3098,12 @@ static inline int dao_forward(struct net_if *iface,
return ret;
}
static int dao_ack_send(struct net_buf *orig,
struct net_rpl_instance *instance,
static int dao_ack_send(struct in6_addr *src,
struct in6_addr *dst,
struct net_if *iface,
struct net_rpl_instance *instance,
uint8_t sequence)
{
struct in6_addr *src = &NET_IPV6_BUF(orig)->dst;
struct net_if *iface = net_nbuf_iface(orig);
struct net_buf *buf;
int ret;
@ -3143,27 +3147,38 @@ static int dao_ack_send(struct net_buf *orig,
return 0;
}
static void forwarding_dao(struct net_rpl_instance *instance,
struct net_rpl_dag *dag,
struct in6_addr *dao_sender,
struct net_buf *buf,
uint8_t sequence,
uint8_t flags,
char *str)
static int forwarding_dao(struct net_rpl_instance *instance,
struct net_rpl_dag *dag,
struct net_buf *buf,
uint8_t sequence,
uint8_t flags,
char *str)
{
struct in6_addr *paddr;
struct in6_addr src;
struct in6_addr dst;
int r = -EINVAL;
paddr = net_rpl_get_parent_addr(instance->iface,
dag->preferred_parent);
if (paddr) {
NET_DBG("%s %s", str, net_sprint_ipv6_addr(paddr));
dao_forward(dag->instance->iface, buf, paddr);
net_ipaddr_copy(&src, &NET_IPV6_BUF(buf)->src);
net_ipaddr_copy(&dst, &NET_IPV6_BUF(buf)->dst);
r = dao_forward(dag->instance->iface, buf, paddr);
if (r < 0) {
return r;
}
if (flags & NET_RPL_DAO_K_FLAG) {
dao_ack_send(buf, instance, dao_sender, sequence);
r = dao_ack_send(&dst, &src, net_nbuf_iface(buf),
instance, sequence);
}
}
return r;
}
static enum net_verdict handle_dao(struct net_buf *buf)
@ -3187,6 +3202,7 @@ static enum net_verdict handle_dao(struct net_buf *buf)
uint8_t flags;
uint8_t subopt_type;
int len;
int r = -EINVAL;
net_rpl_info(buf, "Destination Advertisement Object");
@ -3300,8 +3316,8 @@ static enum net_verdict handle_dao(struct net_buf *buf)
addr.s6_addr);
break;
case NET_RPL_OPTION_TRANSIT:
/* The path sequence and control are ignored. */
frag = net_nbuf_skip(frag, pos, &pos, 2);
/* The flags, path sequence and control are ignored. */
frag = net_nbuf_skip(frag, pos, &pos, 3);
frag = net_nbuf_read_u8(frag, pos, &pos, &lifetime);
break;
}
@ -3350,15 +3366,19 @@ static enum net_verdict handle_dao(struct net_buf *buf)
* if we have one.
*/
if (dag->preferred_parent) {
forwarding_dao(instance, dag, dao_sender,
buf, sequence, flags,
r = forwarding_dao(instance, dag,
buf, sequence, flags,
#if defined(CONFIG_NET_DEBUG_RPL)
"Forwarding no-path DAO to "
"parent"
"Forwarding no-path DAO to "
"parent"
#else
""
""
#endif
);
);
if (r >= 0) {
net_nbuf_unref(buf);
return NET_OK;
}
}
}
@ -3371,7 +3391,7 @@ static enum net_verdict handle_dao(struct net_buf *buf)
if (!nbr) {
nbr = net_ipv6_nbr_add(net_nbuf_iface(buf), dao_sender,
net_nbuf_ll_src(buf), false,
NET_NBR_REACHABLE);
NET_IPV6_NBR_STATE_REACHABLE);
if (nbr) {
/* Set reachable timer */
net_ipv6_nbr_set_reachable_timer(net_nbuf_iface(buf),
@ -3416,15 +3436,18 @@ fwd_dao:
if (learned_from == NET_RPL_ROUTE_UNICAST_DAO) {
if (dag->preferred_parent) {
forwarding_dao(instance, dag,
dao_sender, buf,
sequence, flags,
r = forwarding_dao(instance, dag,
buf, sequence, flags,
#if defined(CONFIG_NET_DEBUG_RPL)
"Forwarding DAO to parent"
"Forwarding DAO to parent"
#else
""
""
#endif
);
);
if (r >= 0) {
net_nbuf_unref(buf);
return NET_OK;
}
}
}
@ -3436,9 +3459,12 @@ static enum net_verdict handle_dao_ack(struct net_buf *buf)
{
net_rpl_info(buf, "Destination Advertisement Object Ack");
/* TODO: Handle DAO ACK properly */
net_stats_update_rpl_dao_ack_recv();
return NET_DROP;
net_nbuf_unref(buf);
return NET_OK;
}
static struct net_icmpv6_handler dodag_info_solicitation_handler = {
@ -3992,7 +4018,7 @@ void net_rpl_init(void)
static struct net_if_link_cb link_cb;
struct in6_addr addr;
NET_DBG("Allocated %d routing entries (%d bytes)",
NET_DBG("Allocated %d routing entries (%zu bytes)",
CONFIG_NET_IPV6_MAX_NEIGHBORS,
sizeof(net_rpl_neighbor_pool));

View file

@ -71,13 +71,14 @@ static char upper_if_set(char chr, bool set)
static void net_tcp_trace(struct net_buf *buf, struct net_tcp *tcp)
{
uint8_t flags = NET_TCP_FLAGS(buf);
uint32_t rel_ack;
uint32_t rel_ack, ack;
ack = sys_get_be32(NET_TCP_BUF(buf)->ack);
if (!tcp->sent_ack) {
rel_ack = 0;
} else {
rel_ack = sys_get_be32(NET_TCP_BUF(buf)->ack) ?
sys_get_be32(NET_TCP_BUF(buf)->ack) - tcp->sent_ack : 0;
rel_ack = ack ? ack - tcp->sent_ack : 0;
}
NET_DBG("buf %p src %u dst %u seq 0x%04x ack 0x%04x (%u) "
@ -86,7 +87,7 @@ static void net_tcp_trace(struct net_buf *buf, struct net_tcp *tcp)
ntohs(NET_TCP_BUF(buf)->src_port),
ntohs(NET_TCP_BUF(buf)->dst_port),
sys_get_be32(NET_TCP_BUF(buf)->seq),
sys_get_be32(NET_TCP_BUF(buf)->ack),
ack,
/* This tells how many bytes we are acking now */
rel_ack,
upper_if_set('u', flags & NET_TCP_URG),

View file

@ -11,10 +11,11 @@ config DNS_RESOLVER
help
This option enables the DNS client side support for Zephyr
if DNS_RESOLVER
config DNS_RESOLVER_ADDITIONAL_BUF_CTR
int
prompt "Additional DNS buffers"
depends on DNS_RESOLVER
default 0
help
Number of additional buffers available for the DNS resolver.
@ -25,7 +26,6 @@ config DNS_RESOLVER_ADDITIONAL_BUF_CTR
config DNS_RESOLVER_ADDITIONAL_QUERIES
int
prompt "Additional DNS queries"
depends on DNS_RESOLVER
range 0 2
default 1
help
@ -33,3 +33,79 @@ config DNS_RESOLVER_ADDITIONAL_QUERIES
generate when the RR ANSWER only contains CNAME(s).
The maximum value of this variable is constrained to avoid
'alias loops'.
config DNS_RESOLVER_MAX_SERVERS
int "Number of DNS server addresses"
range 1 NET_MAX_CONTEXTS
default 1
help
Max number of DNS servers that we can connect to. Normally one
DNS server is enough. Each connection to DNS server will use one
network context.
menuconfig DNS_SERVER_IP_ADDRESSES
bool "Set DNS server IP addresses"
default n
help
Allow DNS IP addresses to be set in config file for
networking applications.
if DNS_SERVER_IP_ADDRESSES
config DNS_SERVER1
string "DNS server 1"
default ""
help
DNS server IP address 1. The address can be either IPv4 or IPv6
address. An optional port number can be given.
Following syntax is supported:
192.0.2.1
192.0.2.1:5353
2001:db8::1
[2001:db8::1]:5353
It is not mandatory to use this Kconfig option at all.
The one calling dns_resolve_init() can use this option or not
to populate the server list. If the DNS server addresses are
set here, then we automatically create default DNS context
for the user.
config DNS_SERVER2
string "DNS server 2"
default ""
help
See help in "DNS server 1" option.
config DNS_SERVER3
string "DNS server 3"
default ""
help
See help in "DNS server 1" option.
config DNS_SERVER4
string "DNS server 4"
default ""
help
See help in "DNS server 1" option.
config DNS_SERVER5
string "DNS server 5"
default ""
help
See help in "DNS server 1" option.
endif # DNS_SERVER_IP_ADDRESSES
config DNS_NUM_CONCUR_QUERIES
int "Number of simultaneous DNS queries per one DNS context"
default 1
help
This defines how many concurrent DNS queries can be generated using
same DNS context. Normally 1 is a good default value.
config NET_DEBUG_DNS_RESOLVE
bool "Debug DNS resolver"
default n
help
Enables DNS resolver code to output debug messages
endif # DNS_RESOLVER

View file

@ -1,5 +1,5 @@
ccflags-y += -I$(srctree)/subsys/net/lib/dns
obj-y := dns_pack.o
obj-y += dns_client.o
obj-$(CONFIG_DNS_RESOLVER) += dns_client.o
obj-$(CONFIG_DNS_RESOLVER) += resolve.o

View file

@ -0,0 +1,907 @@
/** @file
* @brief DNS resolve API
*
* An API for applications to do DNS query.
*/
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#if defined(CONFIG_NET_DEBUG_DNS_RESOLVE)
#define SYS_LOG_DOMAIN "dns/resolve"
#define NET_LOG_ENABLED 1
#endif
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <net/net_ip.h>
#include <net/nbuf.h>
#include <net/dns_resolve.h>
#include "dns_pack.h"
static int dns_write(struct dns_resolve_context *ctx,
int server_idx,
int query_idx,
struct net_buf *dns_data,
struct net_buf *dns_qname);
#define DNS_BUF_TIMEOUT 500 /* ms */
/* RFC 1035, 3.1. Name space definitions
* To simplify implementations, the total length of a domain name (i.e.,
* label octets and label length octets) is restricted to 255 octets or
* less.
*/
#define DNS_MAX_NAME_LEN 255
#define DNS_QUERY_MAX_SIZE (DNS_MSG_HEADER_SIZE + DNS_MAX_NAME_LEN + \
DNS_QTYPE_LEN + DNS_QCLASS_LEN)
/* This value is recommended by RFC 1035 */
#define DNS_RESOLVER_MAX_BUF_SIZE 512
#define DNS_RESOLVER_MIN_BUF 1
#define DNS_RESOLVER_BUF_CTR (DNS_RESOLVER_MIN_BUF + \
CONFIG_DNS_RESOLVER_ADDITIONAL_BUF_CTR)
/* Compressed RR uses a pointer to another RR. So, min size is 12 bytes without
* considering RR payload.
* See https://tools.ietf.org/html/rfc1035#section-4.1.4
*/
#define DNS_ANSWER_PTR_LEN 12
/* See dns_unpack_answer, and also see:
* https://tools.ietf.org/html/rfc1035#section-4.1.2
*/
#define DNS_QUERY_POS 0x0c
#define DNS_IPV4_LEN sizeof(struct in_addr)
#define DNS_IPV6_LEN sizeof(struct in6_addr)
NET_BUF_POOL_DEFINE(dns_msg_pool, DNS_RESOLVER_BUF_CTR,
DNS_RESOLVER_MAX_BUF_SIZE, 0, NULL);
NET_BUF_POOL_DEFINE(dns_qname_pool, DNS_RESOLVER_BUF_CTR, DNS_MAX_NAME_LEN,
0, NULL);
static struct dns_resolve_context dns_default_ctx;
int dns_resolve_init(struct dns_resolve_context *ctx, const char *servers[])
{
#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 addr_len = 0;
int i = 0, idx = 0;
uint16_t port = 0;
int ret, count;
if (!ctx) {
return -ENOENT;
}
if (!servers || !*servers) {
return -ENOENT;
}
if (ctx->is_used) {
return -ENOTEMPTY;
}
memset(ctx, 0, sizeof(*ctx));
for (i = 0; i < CONFIG_DNS_RESOLVER_MAX_SERVERS && servers[i]; i++) {
int j;
char *ptr;
if (*servers[i] == '[') {
#if defined(CONFIG_NET_IPV6)
/* IPv6 address with port number */
struct in6_addr *addr;
char server[INET6_ADDRSTRLEN + 1];
int end;
ptr = strstr(servers[i], "]:");
if (!ptr) {
continue;
}
end = min(INET6_ADDRSTRLEN, ptr - (servers[i] + 1));
memcpy(server, servers[i] + 1, end);
server[end] = '\0';
addr = &net_sin6(&ctx->servers[idx].dns_server)->
sin6_addr;
ret = net_addr_pton(AF_INET6, server, addr);
if (ret < 0 && ret != -EINVAL) {
return ret;
}
if (ret == -EINVAL) {
continue;
}
port = strtol(ptr + 2, NULL, 10);
net_sin6(&ctx->servers[idx].dns_server)->sin6_port =
htons(port);
ctx->servers[idx++].dns_server.family = AF_INET6;
#endif /* CONFIG_NET_IPV6 */
continue;
}
count = j = 0;
while (servers[i][j]) {
if (servers[i][j] == ':') {
count++;
}
j++;
}
if (count == 1) {
#if defined(CONFIG_NET_IPV4)
/* IPv4 address with port number */
char server[NET_IPV4_ADDR_LEN + 1];
struct in_addr *addr;
int end;
ptr = strstr(servers[i], ":");
if (!ptr) {
continue;
}
end = min(NET_IPV4_ADDR_LEN, ptr - servers[i]);
memcpy(server, servers[i], end);
server[end] = '\0';
addr = &net_sin(&ctx->servers[idx].dns_server)->
sin_addr;
ret = net_addr_pton(AF_INET, server, addr);
if (ret < 0 && ret != -EINVAL) {
NET_ERR("Cannot set DNS server %s", server);
return ret;
}
if (ret == -EINVAL) {
continue;
}
port = strtol(ptr + 1, NULL, 10);
net_sin(&ctx->servers[idx].dns_server)->sin_port =
htons(port);
ctx->servers[idx++].dns_server.family = AF_INET;
#endif /* CONFIG_NET_IPV4 */
continue;
}
#if defined(CONFIG_NET_IPV4) && defined(CONFIG_NET_IPV6)
/* First try IPv4 address */
ret = net_addr_pton(AF_INET, servers[i],
&net_sin(&ctx->servers[idx].dns_server)->
sin_addr);
if (ret < 0 && ret != -EINVAL) {
return ret;
}
if (!ret) {
net_sin(&ctx->servers[idx].dns_server)->sin_port =
htons(53);
ctx->servers[idx++].dns_server.family = AF_INET;
} else if (ret == -EINVAL) {
/* Then the address must be IPv6 based */
ret = net_addr_pton(AF_INET6, servers[i],
&net_sin6(&ctx->servers[idx].dns_server)->
sin6_addr);
if (ret < 0 && ret != -EINVAL) {
return ret;
}
if (ret == -EINVAL) {
continue;
}
net_sin6(&ctx->servers[idx].dns_server)->sin6_port =
htons(53);
ctx->servers[idx++].dns_server.family = AF_INET6;
}
#endif
#if defined(CONFIG_NET_IPV4) && !defined(CONFIG_NET_IPV6)
ret = net_addr_pton(AF_INET, servers[i],
&net_sin(&ctx->servers[idx].dns_server)->
sin_addr);
if (ret < 0 && ret != -EINVAL) {
return ret;
}
if (ret == -EINVAL) {
continue;
}
net_sin(&ctx->servers[idx].dns_server)->sin_port = htons(53);
ctx->servers[idx++].dns_server.family = AF_INET;
#endif /* IPv4 && !IPv6 */
#if defined(CONFIG_NET_IPV6) && !defined(CONFIG_NET_IPV4)
ret = net_addr_pton(AF_INET6, servers[i],
&net_sin6(&ctx->servers[idx].dns_server)->sin6_addr);
if (ret < 0 && ret != -EINVAL) {
return ret;
}
if (ret == -EINVAL) {
continue;
}
net_sin6(&ctx->servers[idx].dns_server)->sin6_port = htons(53);
ctx->servers[idx++].dns_server.family = AF_INET6;
#endif /* IPv6 && !IPv4 */
}
for (i = 0, count = 0; i < CONFIG_DNS_RESOLVER_MAX_SERVERS &&
ctx->servers[i].dns_server.family; i++) {
if (ctx->servers[i].dns_server.family == AF_INET6) {
#if defined(CONFIG_NET_IPV6)
local_addr = (struct sockaddr *)&local_addr6;
addr_len = sizeof(struct sockaddr_in6);
#else
continue;
#endif
}
if (ctx->servers[i].dns_server.family == AF_INET) {
#if defined(CONFIG_NET_IPV4)
local_addr = (struct sockaddr *)&local_addr4;
addr_len = sizeof(struct sockaddr_in);
#else
continue;
#endif
}
ret = net_context_get(ctx->servers[i].dns_server.family,
SOCK_DGRAM, IPPROTO_UDP,
&ctx->servers[i].net_ctx);
if (ret < 0) {
NET_DBG("Cannot get net_context (%d)", ret);
return ret;
}
ret = net_context_bind(ctx->servers[i].net_ctx,
local_addr, addr_len);
if (ret < 0) {
NET_DBG("Cannot bind DNS context (%d)", ret);
return ret;
}
count++;
}
if (count == 0) {
/* No servers defined */
NET_DBG("No DNS servers defined.");
return -EINVAL;
}
ctx->is_used = true;
ctx->buf_timeout = DNS_BUF_TIMEOUT;
return 0;
}
static inline int get_cb_slot(struct dns_resolve_context *ctx)
{
int i;
for (i = 0; i < CONFIG_DNS_NUM_CONCUR_QUERIES; i++) {
if (!ctx->queries[i].cb) {
return i;
}
}
return -ENOENT;
}
static inline int get_slot_by_id(struct dns_resolve_context *ctx,
uint16_t dns_id)
{
int i;
for (i = 0; i < CONFIG_DNS_NUM_CONCUR_QUERIES; i++) {
if (ctx->queries[i].cb && ctx->queries[i].id == dns_id) {
return i;
}
}
return -ENOENT;
}
static int dns_read(struct dns_resolve_context *ctx,
struct net_buf *buf,
struct net_buf *dns_data,
uint16_t *dns_id,
struct net_buf *dns_cname,
struct dns_addrinfo *info)
{
/* Helper struct to track the dns msg received from the server */
struct dns_msg_t dns_msg;
uint32_t ttl; /* RR ttl, so far it is not passed to caller */
uint8_t *src, *addr;
int address_size;
/* index that points to the current answer being analyzed */
int answer_ptr;
int data_len;
int offset;
int items;
int ret;
int server_idx, query_idx;
data_len = min(net_nbuf_appdatalen(buf), DNS_RESOLVER_MAX_BUF_SIZE);
offset = net_buf_frags_len(buf) - data_len;
/* TODO: Instead of this temporary copy, just use the net_buf directly.
*/
ret = net_nbuf_linear_copy(dns_data, buf, offset, data_len);
if (ret < 0) {
ret = DNS_EAI_MEMORY;
goto quit;
}
dns_msg.msg = dns_data->data;
dns_msg.msg_size = data_len;
/* The dns_unpack_response_header() has design flaw as it expects
* dns id to be given instead of returning the id to the caller.
* In our case we would like to get it returned instead so that we
* can match the DNS query that we sent. When dns_read() is called,
* we do not know what the DNS id is yet.
*/
*dns_id = dns_unpack_header_id(dns_msg.msg);
query_idx = get_slot_by_id(ctx, *dns_id);
if (query_idx < 0) {
ret = DNS_EAI_SYSTEM;
goto quit;
}
if (dns_header_rcode(dns_msg.msg) == DNS_HEADER_REFUSED) {
ret = DNS_EAI_FAIL;
goto quit;
}
ret = dns_unpack_response_header(&dns_msg, *dns_id);
if (ret < 0) {
ret = DNS_EAI_FAIL;
goto quit;
}
if (dns_header_qdcount(dns_msg.msg) != 1) {
ret = DNS_EAI_FAIL;
goto quit;
}
ret = dns_unpack_response_query(&dns_msg);
if (ret < 0) {
ret = DNS_EAI_FAIL;
goto quit;
}
if (ctx->queries[query_idx].query_type == DNS_QUERY_TYPE_A) {
address_size = DNS_IPV4_LEN;
addr = (uint8_t *)&net_sin(&info->ai_addr)->sin_addr;
info->ai_family = AF_INET;
} else if (ctx->queries[query_idx].query_type == DNS_QUERY_TYPE_AAAA) {
address_size = DNS_IPV6_LEN;
addr = (uint8_t *)&net_sin6(&info->ai_addr)->sin6_addr;
info->ai_family = AF_INET6;
} else {
ret = DNS_EAI_FAMILY;
goto quit;
}
/* while loop to traverse the response */
answer_ptr = DNS_QUERY_POS;
items = 0;
server_idx = 0;
while (server_idx < dns_header_ancount(dns_msg.msg)) {
ret = dns_unpack_answer(&dns_msg, answer_ptr, &ttl);
if (ret < 0) {
ret = DNS_EAI_FAIL;
goto quit;
}
switch (dns_msg.response_type) {
case DNS_RESPONSE_IP:
if (dns_msg.response_length < address_size) {
/* it seems this is a malformed message */
ret = DNS_EAI_FAIL;
goto quit;
}
src = dns_msg.msg + dns_msg.response_position;
memcpy(addr, src, address_size);
info->ai_addrlen = address_size;
ctx->queries[query_idx].cb(DNS_EAI_INPROGRESS, info,
ctx->queries[query_idx].user_data);
items++;
break;
case DNS_RESPONSE_CNAME_NO_IP:
/* Instead of using the QNAME at DNS_QUERY_POS,
* we will use this CNAME
*/
answer_ptr = dns_msg.response_position;
break;
default:
ret = DNS_EAI_FAIL;
goto quit;
}
/* Update the answer offset to point to the next RR (answer) */
dns_msg.answer_offset += DNS_ANSWER_PTR_LEN;
dns_msg.answer_offset += dns_msg.response_length;
server_idx++;
}
/* No IP addresses were found, so we take the last CNAME to generate
* another query. Number of additional queries is controlled via Kconfig
*/
if (items == 0) {
if (dns_msg.response_type == DNS_RESPONSE_CNAME_NO_IP) {
uint16_t pos = dns_msg.response_position;
ret = dns_copy_qname(dns_cname->data, &dns_cname->len,
dns_cname->size, &dns_msg, pos);
if (ret < 0) {
ret = DNS_EAI_SYSTEM;
goto quit;
}
ret = DNS_EAI_AGAIN;
goto finished;
}
}
if (items == 0) {
ret = DNS_EAI_NODATA;
} else {
ret = DNS_EAI_ALLDONE;
}
/* Marks the end of the results */
ctx->queries[query_idx].cb(ret, NULL,
ctx->queries[query_idx].user_data);
if (k_delayed_work_remaining_get(&ctx->queries[query_idx].timer) > 0) {
k_delayed_work_cancel(&ctx->queries[query_idx].timer);
}
ctx->queries[query_idx].cb = NULL;
net_nbuf_unref(buf);
return 0;
finished:
dns_resolve_cancel(ctx, *dns_id);
quit:
net_nbuf_unref(buf);
return ret;
}
static void cb_recv(struct net_context *net_ctx,
struct net_buf *buf,
int status,
void *user_data)
{
struct dns_resolve_context *ctx = user_data;
struct dns_addrinfo info = { 0 };
struct net_buf *dns_cname = NULL;
struct net_buf *dns_data = NULL;
uint16_t dns_id = 0;
int ret, i;
ARG_UNUSED(net_ctx);
if (status) {
ret = DNS_EAI_SYSTEM;
goto quit;
}
dns_data = net_buf_alloc(&dns_msg_pool, ctx->buf_timeout);
if (!dns_data) {
ret = DNS_EAI_MEMORY;
goto quit;
}
dns_cname = net_buf_alloc(&dns_qname_pool, ctx->buf_timeout);
if (!dns_cname) {
ret = DNS_EAI_MEMORY;
goto quit;
}
ret = dns_read(ctx, buf, dns_data, &dns_id, dns_cname, &info);
if (!ret) {
/* We called the callback already in dns_read() if there
* was no errors.
*/
goto free_buf;
}
/* Query again if we got CNAME */
if (ret == DNS_EAI_AGAIN) {
int failure = 0;
int j;
i = get_slot_by_id(ctx, dns_id);
if (i < 0) {
goto cancel;
}
for (j = 0; j < CONFIG_DNS_RESOLVER_MAX_SERVERS; j++) {
if (!ctx->servers[j].net_ctx) {
continue;
}
ret = dns_write(ctx, j, i, dns_data, dns_cname);
if (ret < 0) {
failure++;
}
}
if (failure) {
NET_DBG("DNS cname query failed %d times", failure);
if (failure == j) {
ret = DNS_EAI_SYSTEM;
goto quit;
}
}
goto free_buf;
}
quit:
i = get_slot_by_id(ctx, dns_id);
if (i < 0) {
goto free_buf;
}
cancel:
if (k_delayed_work_remaining_get(&ctx->queries[i].timer) > 0) {
k_delayed_work_cancel(&ctx->queries[i].timer);
}
ctx->queries[i].cb(ret, &info, ctx->queries[i].user_data);
ctx->queries[i].cb = NULL;
free_buf:
if (dns_data) {
net_buf_unref(dns_data);
}
if (dns_cname) {
net_buf_unref(dns_cname);
}
}
static int dns_write(struct dns_resolve_context *ctx,
int server_idx,
int query_idx,
struct net_buf *dns_data,
struct net_buf *dns_qname)
{
enum dns_query_type query_type;
struct net_context *net_ctx;
struct sockaddr *server;
struct net_buf *buf;
int server_addr_len;
uint16_t dns_id;
int ret;
net_ctx = ctx->servers[server_idx].net_ctx;
server = &ctx->servers[server_idx].dns_server;
dns_id = ctx->queries[query_idx].id;
query_type = ctx->queries[query_idx].query_type;
ret = dns_msg_pack_query(dns_data->data, &dns_data->len, dns_data->size,
dns_qname->data, dns_qname->len, dns_id,
(enum dns_rr_type)query_type);
if (ret < 0) {
ret = -EINVAL;
goto quit;
}
buf = net_nbuf_get_tx(net_ctx, ctx->buf_timeout);
if (!buf) {
ret = -ENOMEM;
goto quit;
}
ret = net_nbuf_append(buf, dns_data->len, dns_data->data,
ctx->buf_timeout);
if (ret < 0) {
ret = -ENOMEM;
goto quit;
}
if (server->family == AF_INET) {
server_addr_len = sizeof(struct sockaddr_in);
} else {
server_addr_len = sizeof(struct sockaddr_in6);
}
net_context_recv(net_ctx, cb_recv, K_NO_WAIT, ctx);
ret = net_context_sendto(buf, server, server_addr_len, NULL,
K_NO_WAIT, NULL, NULL);
if (ret < 0) {
NET_DBG("Cannot send query (%d)", ret);
net_nbuf_unref(buf);
goto quit;
}
ret = k_delayed_work_submit(&ctx->queries[query_idx].timer,
ctx->queries[query_idx].timeout);
if (ret < 0) {
NET_DBG("[%u] cannot submit work to server idx %d for id %u "
"timeout %u ret %d",
query_idx, server_idx, dns_id,
ctx->queries[query_idx].timeout, ret);
goto quit;
} else {
NET_DBG("[%u] submitting work to server idx %d for id %u "
"timeout %u",
query_idx, server_idx, dns_id,
ctx->queries[query_idx].timeout);
}
ret = 0;
quit:
return ret;
}
int dns_resolve_cancel(struct dns_resolve_context *ctx, uint16_t dns_id)
{
int i;
i = get_slot_by_id(ctx, dns_id);
if (i < 0) {
return -ENOENT;
}
NET_DBG("Cancelling DNS req %u", dns_id);
if (k_delayed_work_remaining_get(&ctx->queries[i].timer) > 0) {
k_delayed_work_cancel(&ctx->queries[i].timer);
}
ctx->queries[i].cb(DNS_EAI_CANCELED, NULL, ctx->queries[i].user_data);
ctx->queries[i].cb = NULL;
return 0;
}
static void query_timeout(struct k_work *work)
{
struct dns_pending_query *pending_query =
CONTAINER_OF(work, struct dns_pending_query, timer);
NET_DBG("Query timeout DNS req %u", pending_query->id);
dns_resolve_cancel(pending_query->ctx, pending_query->id);
}
int dns_resolve_name(struct dns_resolve_context *ctx,
const char *query,
enum dns_query_type type,
uint16_t *dns_id,
dns_resolve_cb_t cb,
void *user_data,
int32_t timeout)
{
struct net_buf *dns_data;
struct net_buf *dns_qname = NULL;
int ret, i, j = 0;
int failure = 0;
if (!ctx || !ctx->is_used || !query || !cb) {
return -EINVAL;
}
/* Timeout cannot be 0 as we cannot resolve name that fast.
*/
if (timeout == K_NO_WAIT) {
return -EINVAL;
}
i = get_cb_slot(ctx);
if (i < 0) {
return -EAGAIN;
}
ctx->queries[i].cb = cb;
ctx->queries[i].timeout = timeout;
ctx->queries[i].query = query;
ctx->queries[i].query_type = type;
ctx->queries[i].user_data = user_data;
ctx->queries[i].ctx = ctx;
k_delayed_work_init(&ctx->queries[i].timer, query_timeout);
dns_data = net_buf_alloc(&dns_msg_pool, ctx->buf_timeout);
if (!dns_data) {
ret = -ENOMEM;
goto quit;
}
dns_qname = net_buf_alloc(&dns_qname_pool, ctx->buf_timeout);
if (!dns_qname) {
ret = -ENOMEM;
goto quit;
}
ret = dns_msg_pack_qname(&dns_qname->len, dns_qname->data,
DNS_MAX_NAME_LEN, ctx->queries[i].query);
if (ret < 0) {
goto quit;
}
ctx->queries[i].id = sys_rand32_get();
/* Do this immediately after calculating the Id so that the unit
* test will work properly.
*/
if (dns_id) {
*dns_id = ctx->queries[i].id;
NET_DBG("DNS id will be %u", *dns_id);
}
for (j = 0; j < CONFIG_DNS_RESOLVER_MAX_SERVERS; j++) {
if (!ctx->servers[j].net_ctx) {
continue;
}
ret = dns_write(ctx, j, i, dns_data, dns_qname);
if (ret < 0) {
failure++;
continue;
}
/* Do one concurrent query only for each name resolve.
* TODO: Change the i (query index) to do multiple concurrent
* to each server.
*/
break;
}
if (failure) {
NET_DBG("DNS query failed %d times", failure);
if (failure == j) {
ret = -ENOENT;
goto quit;
}
}
ret = 0;
quit:
if (ret < 0) {
if (k_delayed_work_remaining_get(&ctx->queries[i].timer) > 0) {
k_delayed_work_cancel(&ctx->queries[i].timer);
}
ctx->queries[i].cb = NULL;
if (dns_id) {
*dns_id = 0;
}
}
if (dns_data) {
net_buf_unref(dns_data);
}
if (dns_qname) {
net_buf_unref(dns_qname);
}
return ret;
}
int dns_resolve_close(struct dns_resolve_context *ctx)
{
int i;
if (!ctx->is_used) {
return -ENOENT;
}
for (i = 0; i < CONFIG_DNS_RESOLVER_MAX_SERVERS; i++) {
if (ctx->servers[i].net_ctx) {
net_context_put(ctx->servers[i].net_ctx);
}
}
return 0;
}
struct dns_resolve_context *dns_resolve_get_default(void)
{
return &dns_default_ctx;
}
void dns_init_resolver(void)
{
#if defined(CONFIG_DNS_SERVER_IP_ADDRESSES)
static const char *dns_servers[CONFIG_DNS_RESOLVER_MAX_SERVERS + 1];
int count = CONFIG_DNS_RESOLVER_MAX_SERVERS;
int ret;
if (count > 5) {
count = 5;
}
switch (count) {
case 5:
dns_servers[4] = CONFIG_DNS_SERVER5;
/* fallthrough */
case 4:
dns_servers[3] = CONFIG_DNS_SERVER4;
/* fallthrough */
case 3:
dns_servers[2] = CONFIG_DNS_SERVER3;
/* fallthrough */
case 2:
dns_servers[1] = CONFIG_DNS_SERVER2;
/* fallthrough */
case 1:
dns_servers[0] = CONFIG_DNS_SERVER1;
/* fallthrough */
case 0:
break;
}
dns_servers[CONFIG_DNS_RESOLVER_MAX_SERVERS] = NULL;
ret = dns_resolve_init(dns_resolve_get_default(), dns_servers);
if (ret < 0) {
NET_WARN("Cannot initialize DNS resolver (%d)", ret);
}
#endif
}

View file

@ -275,6 +275,7 @@ int _zoap_well_known_core_get(struct zoap_resource *resource,
r = zoap_add_option(&response, ZOAP_OPTION_CONTENT_FORMAT,
&format, sizeof(format));
if (r < 0) {
net_nbuf_unref(buf);
return -EINVAL;
}
@ -298,6 +299,11 @@ done:
zoap_header_set_code(&response, ZOAP_RESPONSE_CODE_BAD_REQUEST);
}
return net_context_sendto(buf, from, sizeof(struct sockaddr_in6),
NULL, 0, NULL, NULL);
r = net_context_sendto(buf, from, sizeof(struct sockaddr_in6),
NULL, 0, NULL, NULL);
if (r < 0) {
net_nbuf_unref(buf);
}
return r;
}

View file

@ -0,0 +1,4 @@
BOARD ?= qemu_x86
CONF_FILE ?= prj.conf
include $(ZEPHYR_BASE)/Makefile.test

View file

@ -0,0 +1,31 @@
CONFIG_NETWORKING=y
CONFIG_RANDOM_GENERATOR=y
CONFIG_TEST_RANDOM_GENERATOR=y
CONFIG_NET_L2_DUMMY=y
CONFIG_DNS_RESOLVER=y
CONFIG_DNS_RESOLVER_MAX_SERVERS=4
CONFIG_DNS_NUM_OF_CONCUR_QUERIES=1
CONFIG_DNS_SERVER_IP_ADDRESSES=y
CONFIG_DNS_SERVER1="192.0.2.2"
CONFIG_DNS_SERVER2="2001:db8::2"
CONFIG_DNS_SERVER3="192.0.2.2:5353"
CONFIG_DNS_SERVER4="[2001:db8::2]:5353"
CONFIG_NET_LOG=y
CONFIG_SYS_LOG_NET_LEVEL=4
CONFIG_SYS_LOG_SHOW_COLOR=y
#CONFIG_NET_DEBUG_DNS_RESOLVE=y
CONFIG_NET_IPV4=y
CONFIG_NET_IPV6=y
CONFIG_NET_IPV6_DAD=n
CONFIG_NET_IPV6_MLD=n
CONFIG_NET_IPV6_ND=n
CONFIG_NET_ARP=n
CONFIG_PRINTK=y
CONFIG_ZTEST=y

View file

@ -0,0 +1,7 @@
ccflags-y += -I$(ZEPHYR_BASE)/subsys/net/lib/dns
ccflags-y += -I${ZEPHYR_BASE}/subsys/net/ip
ccflags-y += -I${ZEPHYR_BASE}/tests/include
include $(ZEPHYR_BASE)/tests/Makefile.test
obj-y = main.o

View file

@ -0,0 +1,656 @@
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include <errno.h>
#include <misc/printk.h>
#include <ztest.h>
#include <net/ethernet.h>
#include <net/buf.h>
#include <net/net_ip.h>
#include <net/net_if.h>
#include <net/dns_resolve.h>
#define NET_LOG_ENABLED 1
#include "net_private.h"
#if defined(CONFIG_NET_DEBUG_DNS_RESOLVE)
#define DBG(fmt, ...) printk(fmt, ##__VA_ARGS__)
#else
#define DBG(fmt, ...)
#endif
#define NAME4 "4.zephyr.test"
#define NAME6 "6.zephyr.test"
#define DNS_TIMEOUT 500 /* ms */
#if defined(CONFIG_NET_IPV6)
/* Interface 1 addresses */
static struct in6_addr my_addr1 = { { { 0x20, 0x01, 0x0d, 0xb8, 1, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0x1 } } };
/* Extra address is assigned to ll_addr */
static struct in6_addr ll_addr = { { { 0xfe, 0x80, 0x43, 0xb8, 0, 0, 0, 0,
0, 0, 0, 0xf2, 0xaa, 0x29, 0x02,
0x04 } } };
#endif
#if defined(CONFIG_NET_IPV4)
/* Interface 1 addresses */
static struct in_addr my_addr2 = { { { 192, 0, 2, 1 } } };
#endif
static struct net_if *iface1;
static bool test_failed;
static bool test_started;
static bool timeout_query;
static struct k_sem wait_data;
static struct k_sem wait_data2;
static uint16_t current_dns_id;
static struct dns_addrinfo addrinfo;
/* this must be higher that the DNS_TIMEOUT */
#define WAIT_TIME (DNS_TIMEOUT + 300)
struct net_if_test {
uint8_t idx;
uint8_t mac_addr[sizeof(struct net_eth_addr)];
struct net_linkaddr ll_addr;
};
static int net_iface_dev_init(struct device *dev)
{
return 0;
}
static uint8_t *net_iface_get_mac(struct device *dev)
{
struct net_if_test *data = dev->driver_data;
if (data->mac_addr[2] == 0x00) {
/* 00-00-5E-00-53-xx Documentation RFC 7042 */
data->mac_addr[0] = 0x00;
data->mac_addr[1] = 0x00;
data->mac_addr[2] = 0x5E;
data->mac_addr[3] = 0x00;
data->mac_addr[4] = 0x53;
data->mac_addr[5] = sys_rand32_get();
}
data->ll_addr.addr = data->mac_addr;
data->ll_addr.len = 6;
return data->mac_addr;
}
static void net_iface_init(struct net_if *iface)
{
uint8_t *mac = net_iface_get_mac(net_if_get_device(iface));
net_if_set_link_addr(iface, mac, sizeof(struct net_eth_addr),
NET_LINK_ETHERNET);
}
static inline int get_slot_by_id(struct dns_resolve_context *ctx,
uint16_t dns_id)
{
int i;
for (i = 0; i < CONFIG_DNS_NUM_CONCUR_QUERIES; i++) {
if (ctx->queries[i].cb && ctx->queries[i].id == dns_id) {
return i;
}
}
return -1;
}
static int sender_iface(struct net_if *iface, struct net_buf *buf)
{
if (!buf->frags) {
DBG("No data to send!\n");
return -ENODATA;
}
if (!timeout_query) {
struct net_if_test *data = iface->dev->driver_data;
struct dns_resolve_context *ctx;
int slot;
DBG("Sending at iface %d %p\n", net_if_get_by_iface(iface),
iface);
if (net_nbuf_iface(buf) != iface) {
DBG("Invalid interface %p, expecting %p\n",
net_nbuf_iface(buf), iface);
test_failed = true;
}
if (net_if_get_by_iface(iface) != data->idx) {
DBG("Invalid interface %d index, expecting %d\n",
data->idx, net_if_get_by_iface(iface));
test_failed = true;
}
ctx = dns_resolve_get_default();
slot = get_slot_by_id(ctx, current_dns_id);
if (slot < 0) {
DBG("Skipping this query dns id %u\n", current_dns_id);
goto out;
}
/* We need to cancel the query manually so that we
* will not get a timeout.
*/
k_delayed_work_cancel(&ctx->queries[slot].timer);
DBG("Calling cb %p with user data %p\n",
ctx->queries[slot].cb,
ctx->queries[slot].user_data);
ctx->queries[slot].cb(DNS_EAI_INPROGRESS,
&addrinfo,
ctx->queries[slot].user_data);
ctx->queries[slot].cb(DNS_EAI_ALLDONE,
NULL,
ctx->queries[slot].user_data);
ctx->queries[slot].cb = NULL;
}
out:
net_nbuf_unref(buf);
return 0;
}
struct net_if_test net_iface1_data;
static struct net_if_api net_iface_api = {
.init = net_iface_init,
.send = sender_iface,
};
#define _ETH_L2_LAYER DUMMY_L2
#define _ETH_L2_CTX_TYPE NET_L2_GET_CTX_TYPE(DUMMY_L2)
NET_DEVICE_INIT_INSTANCE(net_iface1_test,
"iface1",
iface1,
net_iface_dev_init,
&net_iface1_data,
NULL,
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
&net_iface_api,
_ETH_L2_LAYER,
_ETH_L2_CTX_TYPE,
127);
static void test_init(void)
{
struct net_if_addr *ifaddr;
/* The semaphore is there to wait the data to be received. */
k_sem_init(&wait_data, 0, UINT_MAX);
k_sem_init(&wait_data2, 0, UINT_MAX);
iface1 = net_if_get_by_index(0);
((struct net_if_test *)iface1->dev->driver_data)->idx = 0;
#if defined(CONFIG_NET_IPV6)
ifaddr = net_if_ipv6_addr_add(iface1, &my_addr1,
NET_ADDR_MANUAL, 0);
if (!ifaddr) {
DBG("Cannot add IPv6 address %s\n",
net_sprint_ipv6_addr(&my_addr1));
assert_not_null(ifaddr, "addr1");
}
/* For testing purposes we need to set the adddresses preferred */
ifaddr->addr_state = NET_ADDR_PREFERRED;
ifaddr = net_if_ipv6_addr_add(iface1, &ll_addr,
NET_ADDR_MANUAL, 0);
if (!ifaddr) {
DBG("Cannot add IPv6 address %s\n",
net_sprint_ipv6_addr(&ll_addr));
assert_not_null(ifaddr, "ll_addr");
}
ifaddr->addr_state = NET_ADDR_PREFERRED;
#endif
#if defined(CONFIG_NET_IPV4)
ifaddr = net_if_ipv4_addr_add(iface1, &my_addr2,
NET_ADDR_MANUAL, 0);
if (!ifaddr) {
DBG("Cannot add IPv4 address %s\n",
net_sprint_ipv4_addr(&my_addr2));
assert_not_null(ifaddr, "addr2");
}
ifaddr->addr_state = NET_ADDR_PREFERRED;
#endif
net_if_up(iface1);
/* The interface might receive data which might fail the checks
* in the iface sending function, so we need to reset the failure
* flag.
*/
test_failed = false;
test_started = true;
}
void dns_result_cb_dummy(enum dns_resolve_status status,
struct dns_addrinfo *info,
void *user_data)
{
return;
}
static void dns_query_invalid_timeout(void)
{
int ret;
ret = dns_get_addr_info(NAME6,
DNS_QUERY_TYPE_AAAA,
NULL,
dns_result_cb_dummy,
NULL,
K_NO_WAIT);
assert_equal(ret, -EINVAL, "Wrong return code for timeout");
}
static void dns_query_invalid_context(void)
{
int ret;
ret = dns_resolve_name(NULL,
NAME6,
DNS_QUERY_TYPE_AAAA,
NULL,
dns_result_cb_dummy,
NULL,
DNS_TIMEOUT);
assert_equal(ret, -EINVAL, "Wrong return code for context");
}
static void dns_query_invalid_callback(void)
{
int ret;
ret = dns_get_addr_info(NAME6,
DNS_QUERY_TYPE_AAAA,
NULL,
NULL,
NULL,
DNS_TIMEOUT);
assert_equal(ret, -EINVAL, "Wrong return code for callback");
}
static void dns_query_invalid_query(void)
{
int ret;
ret = dns_get_addr_info(NULL,
DNS_QUERY_TYPE_AAAA,
NULL,
dns_result_cb_dummy,
NULL,
DNS_TIMEOUT);
assert_equal(ret, -EINVAL, "Wrong return code for query");
}
void dns_result_cb_timeout(enum dns_resolve_status status,
struct dns_addrinfo *info,
void *user_data)
{
int expected_status = POINTER_TO_INT(user_data);
if (expected_status != status) {
DBG("Result status %d\n", status);
DBG("Expected status %d\n", expected_status);
assert_equal(expected_status, status, "Invalid status");
}
k_sem_give(&wait_data);
}
static void dns_query_server_count(void)
{
struct dns_resolve_context *ctx = dns_resolve_get_default();
int i, count = 0;
for (i = 0; i < CONFIG_DNS_RESOLVER_MAX_SERVERS; i++) {
if (!ctx->is_used) {
continue;
}
if (!ctx->servers[i].net_ctx) {
continue;
}
count++;
}
assert_equal(count, CONFIG_DNS_RESOLVER_MAX_SERVERS,
"Invalid number of servers");
}
static void dns_query_ipv4_server_count(void)
{
struct dns_resolve_context *ctx = dns_resolve_get_default();
int i, count = 0, port = 0;
for (i = 0; i < CONFIG_DNS_RESOLVER_MAX_SERVERS; i++) {
if (!ctx->is_used) {
continue;
}
if (!ctx->servers[i].net_ctx) {
continue;
}
if (ctx->servers[i].dns_server.family == AF_INET) {
count++;
}
if (net_sin(&ctx->servers[i].dns_server)->sin_port ==
ntohs(53)) {
port++;
}
}
assert_equal(count, 2, "Invalid number of IPv4 servers");
assert_equal(port, 2, "Invalid number of IPv4 servers with port 53");
}
static void dns_query_ipv6_server_count(void)
{
struct dns_resolve_context *ctx = dns_resolve_get_default();
int i, count = 0, port = 0;
for (i = 0; i < CONFIG_DNS_RESOLVER_MAX_SERVERS; i++) {
if (!ctx->is_used) {
continue;
}
if (!ctx->servers[i].net_ctx) {
continue;
}
if (ctx->servers[i].dns_server.family == AF_INET6) {
count++;
}
if (net_sin6(&ctx->servers[i].dns_server)->sin6_port ==
ntohs(53)) {
port++;
}
}
assert_equal(count, 2, "Invalid number of IPv6 servers");
assert_equal(port, 2, "Invalid number of IPv6 servers with port 53");
}
static void dns_query_too_many(void)
{
int expected_status = DNS_EAI_CANCELED;
int ret;
timeout_query = true;
ret = dns_get_addr_info(NAME4,
DNS_QUERY_TYPE_A,
NULL,
dns_result_cb_timeout,
INT_TO_POINTER(expected_status),
DNS_TIMEOUT);
assert_equal(ret, 0, "Cannot create IPv4 query");
ret = dns_get_addr_info(NAME4,
DNS_QUERY_TYPE_A,
NULL,
dns_result_cb_dummy,
INT_TO_POINTER(expected_status),
DNS_TIMEOUT);
assert_equal(ret, -EAGAIN, "Should have run out of space");
if (k_sem_take(&wait_data, WAIT_TIME)) {
assert_true(false, "Timeout while waiting data");
}
timeout_query = false;
}
static void dns_query_ipv4_timeout(void)
{
int expected_status = DNS_EAI_CANCELED;
int ret;
timeout_query = true;
ret = dns_get_addr_info(NAME4,
DNS_QUERY_TYPE_A,
NULL,
dns_result_cb_timeout,
INT_TO_POINTER(expected_status),
DNS_TIMEOUT);
assert_equal(ret, 0, "Cannot create IPv4 query");
if (k_sem_take(&wait_data, WAIT_TIME)) {
assert_true(false, "Timeout while waiting data");
}
timeout_query = false;
}
static void dns_query_ipv6_timeout(void)
{
int expected_status = DNS_EAI_CANCELED;
int ret;
timeout_query = true;
ret = dns_get_addr_info(NAME6,
DNS_QUERY_TYPE_AAAA,
NULL,
dns_result_cb_timeout,
INT_TO_POINTER(expected_status),
DNS_TIMEOUT);
assert_equal(ret, 0, "Cannot create IPv6 query");
if (k_sem_take(&wait_data, WAIT_TIME)) {
assert_true(false, "Timeout while waiting data");
}
timeout_query = false;
}
static void verify_cancelled(void)
{
struct dns_resolve_context *ctx = dns_resolve_get_default();
int i, count = 0, timer_not_stopped = 0;
for (i = 0; i < CONFIG_DNS_NUM_CONCUR_QUERIES; i++) {
if (ctx->queries[i].cb) {
count++;
}
if (k_delayed_work_remaining_get(&ctx->queries[i].timer) > 0) {
timer_not_stopped++;
}
}
assert_equal(count, 0, "Not all pending queries vere cancelled");
assert_equal(timer_not_stopped, 0, "Not all timers vere cancelled");
}
static void dns_query_ipv4_cancel(void)
{
int expected_status = DNS_EAI_CANCELED;
uint16_t dns_id;
int ret;
timeout_query = true;
ret = dns_get_addr_info(NAME4,
DNS_QUERY_TYPE_A,
&dns_id,
dns_result_cb_timeout,
INT_TO_POINTER(expected_status),
DNS_TIMEOUT);
assert_equal(ret, 0, "Cannot create IPv4 query");
ret = dns_cancel_addr_info(dns_id);
assert_equal(ret, 0, "Cannot cancel IPv4 query");
if (k_sem_take(&wait_data, WAIT_TIME)) {
assert_true(false, "Timeout while waiting data");
}
verify_cancelled();
}
static void dns_query_ipv6_cancel(void)
{
int expected_status = DNS_EAI_CANCELED;
uint16_t dns_id;
int ret;
timeout_query = true;
ret = dns_get_addr_info(NAME6,
DNS_QUERY_TYPE_AAAA,
&dns_id,
dns_result_cb_timeout,
INT_TO_POINTER(expected_status),
DNS_TIMEOUT);
assert_equal(ret, 0, "Cannot create IPv6 query");
ret = dns_cancel_addr_info(dns_id);
assert_equal(ret, 0, "Cannot cancel IPv6 query");
if (k_sem_take(&wait_data, WAIT_TIME)) {
assert_true(false, "Timeout while waiting data");
}
verify_cancelled();
}
struct expected_status {
int status1;
int status2;
const char *caller;
};
void dns_result_cb(enum dns_resolve_status status,
struct dns_addrinfo *info,
void *user_data)
{
struct expected_status *expected = user_data;
if (status != expected->status1 && status != expected->status2) {
DBG("Result status %d\n", status);
DBG("Expected status1 %d\n", expected->status1);
DBG("Expected status2 %d\n", expected->status2);
DBG("Caller %s\n", expected->caller);
assert_true(false, "Invalid status");
}
k_sem_give(&wait_data2);
}
static void dns_query_ipv4(void)
{
struct expected_status status = {
.status1 = DNS_EAI_INPROGRESS,
.status2 = DNS_EAI_ALLDONE,
.caller = __func__,
};
int ret;
timeout_query = false;
ret = dns_get_addr_info(NAME4,
DNS_QUERY_TYPE_A,
&current_dns_id,
dns_result_cb,
&status,
DNS_TIMEOUT);
assert_equal(ret, 0, "Cannot create IPv4 query");
DBG("Query id %u\n", current_dns_id);
k_yield(); /* mandatory so that net_if send func gets to run */
if (k_sem_take(&wait_data2, WAIT_TIME)) {
assert_true(false, "Timeout while waiting data");
}
}
static void dns_query_ipv6(void)
{
struct expected_status status = {
.status1 = DNS_EAI_INPROGRESS,
.status2 = DNS_EAI_ALLDONE,
.caller = __func__,
};
int ret;
timeout_query = false;
ret = dns_get_addr_info(NAME6,
DNS_QUERY_TYPE_AAAA,
&current_dns_id,
dns_result_cb,
&status,
DNS_TIMEOUT);
assert_equal(ret, 0, "Cannot create IPv6 query");
DBG("Query id %u\n", current_dns_id);
k_yield(); /* mandatory so that net_if send func gets to run */
if (k_sem_take(&wait_data2, WAIT_TIME)) {
assert_true(false, "Timeout while waiting data");
}
}
void test_main(void)
{
ztest_test_suite(dns_tests,
ztest_unit_test(test_init),
ztest_unit_test(dns_query_invalid_timeout),
ztest_unit_test(dns_query_invalid_context),
ztest_unit_test(dns_query_invalid_callback),
ztest_unit_test(dns_query_invalid_query),
ztest_unit_test(dns_query_too_many),
ztest_unit_test(dns_query_server_count),
ztest_unit_test(dns_query_ipv4_server_count),
ztest_unit_test(dns_query_ipv6_server_count),
ztest_unit_test(dns_query_ipv4_timeout),
ztest_unit_test(dns_query_ipv6_timeout),
ztest_unit_test(dns_query_ipv4_cancel),
ztest_unit_test(dns_query_ipv6_cancel),
ztest_unit_test(dns_query_ipv4),
ztest_unit_test(dns_query_ipv6));
ztest_run_test_suite(dns_tests);
}

View file

@ -0,0 +1,6 @@
[test]
tags = dns net
build_only = false
platform_whitelist = qemu_x86
timeout = 10800
slow = True

View file

@ -440,7 +440,7 @@ static bool net_test_send_ns(void)
&in6addr_my,
&iface->link_addr,
false,
NET_NBR_REACHABLE);
NET_IPV6_NBR_STATE_REACHABLE);
if (!nbr) {
TC_ERROR("Cannot add to neighbor cache\n");
return false;
@ -484,7 +484,7 @@ static bool net_test_nbr_lookup_ok(void)
net_sprint_ipv6_addr(&peer_addr),
net_sprint_ll_addr(llstorage->addr, llstorage->len));
net_ipv6_nbr_data(nbr)->state = NET_NBR_REACHABLE;
net_ipv6_nbr_data(nbr)->state = NET_IPV6_NBR_STATE_REACHABLE;
return true;
}