Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions include/net/net_pkt.h
Original file line number Diff line number Diff line change
Expand Up @@ -1359,6 +1359,19 @@ void net_pkt_get_info(struct k_mem_slab **rx,
struct net_buf_pool **rx_data,
struct net_buf_pool **tx_data);

/**
* @brief Get source socket address.
*
* @param pkt Nework packet
* @param addr Source socket address
* @param addrlen The length of source socket address
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once semantics of *addrlen figure out (comment below), this docstring should describe what gets there on input, what on output.

* @return 0 on success, <0 otherwise.
*/

int net_pkt_get_src_addr(struct net_pkt *pkt,
struct sockaddr *addr,
socklen_t addrlen);

#if defined(CONFIG_NET_DEBUG_NET_PKT)
/**
* @brief Debug helper to print out the buffer allocations
Expand Down
6 changes: 6 additions & 0 deletions include/net/socket.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ int zsock_listen(int sock, int backlog);
int zsock_accept(int sock, struct sockaddr *addr, socklen_t *addrlen);
ssize_t zsock_send(int sock, const void *buf, size_t len, int flags);
ssize_t zsock_recv(int sock, void *buf, size_t max_len, int flags);
ssize_t zsock_sendto(int sock, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
ssize_t zsock_recvfrom(int sock, void *buf, size_t max_len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);
int zsock_fcntl(int sock, int cmd, int flags);
int zsock_poll(struct zsock_pollfd *fds, int nfds, int timeout);
int zsock_inet_pton(sa_family_t family, const char *src, void *dst);
Expand All @@ -78,6 +82,8 @@ int zsock_getaddrinfo(const char *host, const char *service,
#define send zsock_send
#define recv zsock_recv
#define fcntl zsock_fcntl
#define sendto zsock_sendto
#define recvfrom zsock_recvfrom

#define poll zsock_poll
#define pollfd zsock_pollfd
Expand Down
15 changes: 15 additions & 0 deletions subsys/net/ip/net_context.c
Original file line number Diff line number Diff line change
Expand Up @@ -2073,6 +2073,16 @@ static int sendto(struct net_pkt *pkt,
}
#endif /* CONFIG_NET_TCP */

#if defined(CONFIG_NET_UDP)
/* Bind default address and port only if UDP */
if (net_context_get_ip_proto(context) == IPPROTO_UDP) {
ret = bind_default(context);
if (ret) {
return ret;
}
}
#endif /* CONFIG_NET_UDP */

if (!dst_addr) {
return -EDESTADDRREQ;
}
Expand Down Expand Up @@ -2312,6 +2322,11 @@ static int recv_udp(struct net_context *context,
context->conn_handler = NULL;
}

ret = bind_default(context);
if (ret) {
return ret;
}

#if defined(CONFIG_NET_IPV6)
if (net_context_get_family(context) == AF_INET6) {
if (net_sin6_ptr(&context->local)->sin6_addr) {
Expand Down
55 changes: 55 additions & 0 deletions subsys/net/ip/net_pkt.c
Original file line number Diff line number Diff line change
Expand Up @@ -1654,6 +1654,61 @@ void net_pkt_get_info(struct k_mem_slab **rx,
}
}

int net_pkt_get_src_addr(struct net_pkt *pkt, struct sockaddr *addr,
socklen_t addrlen)
{
enum net_ip_protocol proto;
sa_family_t family;

if (!addr || !pkt) {
return -EINVAL;
}

family = net_pkt_family(pkt);

if (IS_ENABLED(CONFIG_NET_IPV6) && family == AF_INET6) {
struct sockaddr_in6 *addr6 = net_sin6(addr);

if (addrlen < sizeof(struct sockaddr_in6)) {
return -EINVAL;
}

net_ipaddr_copy(&addr6->sin6_addr, &NET_IPV6_HDR(pkt)->src);
proto = NET_IPV6_HDR(pkt)->nexthdr;

if (IS_ENABLED(CONFIG_NET_TCP) && proto == IPPROTO_TCP) {
addr6->sin6_port = net_pkt_tcp_data(pkt)->src_port;
} else if (IS_ENABLED(CONFIG_NET_UDP) && proto == IPPROTO_UDP) {
addr6->sin6_port = net_pkt_udp_data(pkt)->src_port;
} else {
return -ENOTSUP;
}

} else if (IS_ENABLED(CONFIG_NET_IPV4) && family == AF_INET) {
struct sockaddr_in *addr4 = net_sin(addr);

if (addrlen < sizeof(struct sockaddr_in)) {
return -EINVAL;
}

net_ipaddr_copy(&addr4->sin_addr, &NET_IPV4_HDR(pkt)->src);
proto = NET_IPV4_HDR(pkt)->proto;

if (IS_ENABLED(CONFIG_NET_TCP) && proto == IPPROTO_TCP) {
addr4->sin_port = net_pkt_tcp_data(pkt)->src_port;
} else if (IS_ENABLED(CONFIG_NET_UDP) && proto == IPPROTO_UDP) {
addr4->sin_port = net_pkt_udp_data(pkt)->src_port;
} else {
return -ENOTSUP;
}

} else {
return -ENOTSUP;
}

return 0;
}

#if defined(CONFIG_NET_DEBUG_NET_PKT)
void net_pkt_print(void)
{
Expand Down
58 changes: 51 additions & 7 deletions subsys/net/lib/sockets/sockets.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,11 +145,12 @@ static void zsock_received_cb(struct net_context *ctx, struct net_pkt *pkt,
/* Normal packet */
net_pkt_set_eof(pkt, false);

/* We don't care about packet header, so get rid of it asap */
header_len = net_pkt_appdata(pkt) - pkt->frags->data;
net_buf_pull(pkt->frags, header_len);

if (net_context_get_type(ctx) == SOCK_STREAM) {
/* TCP: we don't care about packet header, get rid of it asap.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this conditionalizing, leading to code duplication? If we (may) need a packet header, let's keep it here, and consistently remove in zsock_recvfrom.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initially, I prefer to keep the packet header for both cases. But I found zsock_recv_stream() needs to be modified a lot because packet header isn't dropped. I will modify this to prefer consistency.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, you may be right - and we can't return src addr for an arbitrary TCP recv anyway (only for recv() which starts to consume a new packet). Well, that's why it's useful to know why something was implemented this or that way, so having extra info in the commit messages or PR comments is helpful. And yeah, I'd appreciate your giving another thought to trying to avoid that code duplication - if it will lead to only more code being added, sure, it's ok to leave it like that.

* UDP: keep packet header to support recvfrom().
*/
header_len = net_pkt_appdata(pkt) - pkt->frags->data;
net_buf_pull(pkt->frags, header_len);
net_context_update_recv_wnd(ctx, -net_pkt_appdatalen(pkt));
}

Expand Down Expand Up @@ -213,12 +214,20 @@ int zsock_accept(int sock, struct sockaddr *addr, socklen_t *addrlen)

ssize_t zsock_send(int sock, const void *buf, size_t len, int flags)
{
ARG_UNUSED(flags);
return zsock_sendto(sock, buf, len, flags, NULL, 0);
}

ssize_t zsock_sendto(int sock, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen)
{
int err;
struct net_pkt *send_pkt;
s32_t timeout = K_FOREVER;
struct net_context *ctx = INT_TO_POINTER(sock);
size_t max_len = net_if_get_mtu(net_context_get_iface(ctx));
enum net_sock_type sock_type = net_context_get_type(ctx);

ARG_UNUSED(flags);

if (sock_is_nonblock(ctx)) {
timeout = K_NO_WAIT;
Expand Down Expand Up @@ -249,7 +258,20 @@ ssize_t zsock_send(int sock, const void *buf, size_t len, int flags)
return -1;
}

err = net_context_send(send_pkt, /*cb*/NULL, timeout, NULL, NULL);
/* Register the callback before sending in order to receive the response
* from the peer.
*/
SET_ERRNO(net_context_recv(ctx, zsock_received_cb, K_NO_WAIT, NULL));

if (sock_type == SOCK_DGRAM) {
err = net_context_sendto(send_pkt, dest_addr, addrlen, NULL,
timeout, NULL, NULL);
} else if (sock_type == SOCK_STREAM) {
err = net_context_send(send_pkt, NULL, timeout, NULL, NULL);
} else {
__ASSERT(0, "Unknown socket type");
}

if (err < 0) {
net_pkt_unref(send_pkt);
errno = -err;
Expand All @@ -259,7 +281,9 @@ ssize_t zsock_send(int sock, const void *buf, size_t len, int flags)
return len;
}

static inline ssize_t zsock_recv_stream(struct net_context *ctx, void *buf, size_t max_len)
static inline ssize_t zsock_recv_stream(struct net_context *ctx,
void *buf,
size_t max_len)
{
size_t recv_len = 0;
s32_t timeout = K_FOREVER;
Expand Down Expand Up @@ -333,11 +357,18 @@ static inline ssize_t zsock_recv_stream(struct net_context *ctx, void *buf, size
}

ssize_t zsock_recv(int sock, void *buf, size_t max_len, int flags)
{
return zsock_recvfrom(sock, buf, max_len, flags, NULL, NULL);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is right. zsock_send() should be done like this.

}

ssize_t zsock_recvfrom(int sock, void *buf, size_t max_len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen)
{
ARG_UNUSED(flags);
struct net_context *ctx = INT_TO_POINTER(sock);
enum net_sock_type sock_type = net_context_get_type(ctx);
size_t recv_len = 0;
unsigned int header_len;

if (sock_type == SOCK_DGRAM) {

Expand All @@ -354,6 +385,19 @@ ssize_t zsock_recv(int sock, void *buf, size_t max_len, int flags)
return -1;
}

if (src_addr && addrlen) {
int rv;

rv = net_pkt_get_src_addr(pkt, src_addr, *addrlen);
if (rv < 0) {
errno = rv;
return -1;
}
}
/* Remove packet header since we've handled src addr and port */
header_len = net_pkt_appdata(pkt) - pkt->frags->data;
net_buf_pull(pkt->frags, header_len);

recv_len = net_pkt_appdatalen(pkt);
if (recv_len > max_len) {
recv_len = max_len;
Expand Down
9 changes: 5 additions & 4 deletions tests/net/socket/udp/prj.conf
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ CONFIG_NEWLIB_LIBC=y
# Networking config
CONFIG_NETWORKING=y
CONFIG_NET_IPV4=y
CONFIG_NET_IPV6=n
CONFIG_NET_IPV6=y
CONFIG_NET_UDP=y
CONFIG_NET_SOCKETS=y
CONFIG_NET_SOCKETS_POSIX_NAMES=y
Expand All @@ -13,13 +13,14 @@ CONFIG_NET_SOCKETS_POSIX_NAMES=y
CONFIG_TEST_RANDOM_GENERATOR=y

# Network address config
#CONFIG_NET_APP_SETTINGS=y
#CONFIG_NET_APP_MY_IPV4_ADDR="192.0.2.1"
#CONFIG_NET_APP_PEER_IPV4_ADDR="192.0.2.2"
CONFIG_NET_APP_SETTINGS=y
CONFIG_NET_APP_MY_IPV4_ADDR="192.0.2.1"
CONFIG_NET_APP_MY_IPV6_ADDR="2001:db8::1"

# Network debug config
#CONFIG_NET_LOG=y
#CONFIG_NET_DEBUG_SOCKETS=y
#CONFIG_SYS_LOG_NET_LEVEL=4
CONFIG_MAIN_STACK_SIZE=2048

CONFIG_ZTEST=y
Loading