Skip to content

Commit c6c021b

Browse files
jukkarfabiobaltieri
authored andcommitted
net: context: Add helpers for figuring out local endpoint address
We usually cannot use context->local for established TCP connections because the local address is not updated for TCP if we are bound to any address. So create helper that try to figure out the end point addresses. Signed-off-by: Jukka Rissanen <jukka.rissanen@nordicsemi.no>
1 parent b26b0e7 commit c6c021b

File tree

4 files changed

+119
-0
lines changed

4 files changed

+119
-0
lines changed

subsys/net/ip/net_context.c

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3181,6 +3181,51 @@ int net_context_get_option(struct net_context *context,
31813181
return ret;
31823182
}
31833183

3184+
int net_context_get_local_addr(struct net_context *ctx,
3185+
struct sockaddr *addr,
3186+
socklen_t *addrlen)
3187+
{
3188+
if (ctx == NULL || addr == NULL || addrlen == NULL) {
3189+
return -EINVAL;
3190+
}
3191+
3192+
if (IS_ENABLED(CONFIG_NET_TCP) &&
3193+
net_context_get_type(ctx) == SOCK_STREAM) {
3194+
return net_tcp_endpoint_copy(ctx, addr, NULL, addrlen);
3195+
}
3196+
3197+
if (IS_ENABLED(CONFIG_NET_UDP) && net_context_get_type(ctx) == SOCK_DGRAM) {
3198+
socklen_t newlen;
3199+
3200+
if (IS_ENABLED(CONFIG_NET_IPV4) && ctx->local.family == AF_INET) {
3201+
newlen = MIN(*addrlen, sizeof(struct sockaddr_in));
3202+
3203+
net_sin(addr)->sin_family = AF_INET;
3204+
net_sin(addr)->sin_port = net_sin_ptr(&ctx->local)->sin_port;
3205+
memcpy(&net_sin(addr)->sin_addr,
3206+
net_sin_ptr(&ctx->local)->sin_addr,
3207+
sizeof(struct in_addr));
3208+
3209+
} else if (IS_ENABLED(CONFIG_NET_IPV6) && ctx->local.family == AF_INET6) {
3210+
newlen = MIN(*addrlen, sizeof(struct sockaddr_in6));
3211+
3212+
net_sin6(addr)->sin6_family = AF_INET6;
3213+
net_sin6(addr)->sin6_port = net_sin6_ptr(&ctx->local)->sin6_port;
3214+
memcpy(&net_sin6(addr)->sin6_addr,
3215+
net_sin6_ptr(&ctx->local)->sin6_addr,
3216+
sizeof(struct in6_addr));
3217+
} else {
3218+
return -EAFNOSUPPORT;
3219+
}
3220+
3221+
*addrlen = newlen;
3222+
3223+
return 0;
3224+
}
3225+
3226+
return -ENOPROTOOPT;
3227+
}
3228+
31843229
void net_context_foreach(net_context_cb_t cb, void *user_data)
31853230
{
31863231
int i;

subsys/net/ip/net_private.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,9 @@ extern bool net_context_is_recv_pktinfo_set(struct net_context *context);
8181
extern void net_pkt_init(void);
8282
extern void net_tc_tx_init(void);
8383
extern void net_tc_rx_init(void);
84+
int net_context_get_local_addr(struct net_context *context,
85+
struct sockaddr *addr,
86+
socklen_t *addrlen);
8487
#else
8588
static inline void net_context_init(void) { }
8689
static inline void net_pkt_init(void) { }
@@ -106,6 +109,17 @@ static inline bool net_context_is_recv_pktinfo_set(struct net_context *context)
106109
ARG_UNUSED(context);
107110
return false;
108111
}
112+
113+
static inline int net_context_get_local_addr(struct net_context *context,
114+
struct sockaddr *addr,
115+
socklen_t *addrlen)
116+
{
117+
ARG_UNUSED(context);
118+
ARG_UNUSED(addr);
119+
ARG_UNUSED(addrlen);
120+
121+
return -ENOTSUP;
122+
}
109123
#endif
110124

111125
#if defined(CONFIG_NET_NATIVE)

subsys/net/ip/tcp.c

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,51 @@ static int tcp_endpoint_set(union tcp_endpoint *ep, struct net_pkt *pkt,
239239
return ret;
240240
}
241241

242+
int net_tcp_endpoint_copy(struct net_context *ctx,
243+
struct sockaddr *local,
244+
struct sockaddr *peer,
245+
socklen_t *addrlen)
246+
{
247+
const struct tcp *conn = ctx->tcp;
248+
socklen_t newlen = ctx->local.family == AF_INET ?
249+
sizeof(struct sockaddr_in) :
250+
sizeof(struct sockaddr_in6);
251+
252+
if (local != NULL) {
253+
/* If we are connected, then get the address we are actually
254+
* using, otherwise get the address we are bound as these might
255+
* be different if we are bound to any address.
256+
*/
257+
if (conn->state < TCP_ESTABLISHED) {
258+
if (IS_ENABLED(CONFIG_NET_IPV4) && ctx->local.family == AF_INET) {
259+
memcpy(&net_sin(local)->sin_addr,
260+
net_sin_ptr(&ctx->local)->sin_addr,
261+
sizeof(struct in_addr));
262+
net_sin(local)->sin_port = net_sin_ptr(&ctx->local)->sin_port;
263+
net_sin(local)->sin_family = AF_INET;
264+
} else if (IS_ENABLED(CONFIG_NET_IPV4) && ctx->local.family == AF_INET6) {
265+
memcpy(&net_sin6(local)->sin6_addr,
266+
net_sin6_ptr(&ctx->local)->sin6_addr,
267+
sizeof(struct in6_addr));
268+
net_sin6(local)->sin6_port = net_sin6_ptr(&ctx->local)->sin6_port;
269+
net_sin6(local)->sin6_family = AF_INET6;
270+
net_sin6(local)->sin6_scope_id =
271+
net_sin6_ptr(&ctx->local)->sin6_scope_id;
272+
} else {
273+
return -EINVAL;
274+
}
275+
} else {
276+
memcpy(local, &conn->src.sa, newlen);
277+
}
278+
}
279+
280+
if (peer != NULL) {
281+
memcpy(local, &conn->dst.sa, newlen);
282+
}
283+
284+
return 0;
285+
}
286+
242287
static const char *tcp_flags(uint8_t flags)
243288
{
244289
#define BUF_SIZE 25 /* 6 * 4 + 1 */

subsys/net/ip/tcp_internal.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,21 @@ static inline void net_tcp_reply_rst(struct net_pkt *pkt)
448448
}
449449
#endif
450450

451+
/**
452+
* @brief Get the TCP connection endpoint information.
453+
*
454+
* @param context Network context
455+
* @param local TCP connection local socket information is copied here
456+
* @param peer TCP connection peer socket information is copied here
457+
* @param addrlen Size of the sockaddr struct. Copied size is returned.
458+
*
459+
* @return <0 if there was an error, 0 if ok
460+
*/
461+
int net_tcp_endpoint_copy(struct net_context *ctx,
462+
struct sockaddr *local,
463+
struct sockaddr *peer,
464+
socklen_t *addrlen);
465+
451466
#ifdef __cplusplus
452467
}
453468
#endif

0 commit comments

Comments
 (0)