Skip to content

Commit cd0b195

Browse files
rluboskartben
authored andcommitted
net: connection: Make it possible to update local address
Allow to update the local address on a registered connection when rebinding. This is needed for packet sockets, as by default packet socket will be bound to "any" interface (interface index 0), and interface index is part of the local address registered for packet socket. In order to be able to explicitly bind to a specific interface later, it needs to be possible to update the local address registered for the connection, as we need to update the interface index, which is used by net_conn_packet_input() for packet filtering. Signed-off-by: Robert Lubos <[email protected]>
1 parent 6c788e1 commit cd0b195

File tree

3 files changed

+104
-80
lines changed

3 files changed

+104
-80
lines changed

subsys/net/ip/connection.c

Lines changed: 69 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -322,56 +322,30 @@ static int net_conn_change_remote(struct net_conn *conn,
322322
return 0;
323323
}
324324

325-
int net_conn_register(uint16_t proto, enum net_sock_type type, uint8_t family,
326-
const struct sockaddr *remote_addr,
327-
const struct sockaddr *local_addr,
328-
uint16_t remote_port,
329-
uint16_t local_port,
330-
struct net_context *context,
331-
net_conn_cb_t cb,
332-
void *user_data,
333-
struct net_conn_handle **handle)
325+
static int net_conn_change_local(struct net_conn *conn,
326+
const struct sockaddr *local_addr,
327+
uint16_t local_port)
334328
{
335-
struct net_conn *conn;
336-
uint8_t flags = 0U;
337-
int ret;
338-
339-
conn = conn_find_handler(context != NULL ? net_context_get_iface(context) : NULL,
340-
proto, family, remote_addr, local_addr,
341-
remote_port, local_port,
342-
context != NULL ?
343-
net_context_is_reuseport_set(context) :
344-
false);
345-
if (conn) {
346-
NET_ERR("Identical connection handler %p already found.", conn);
347-
return -EADDRINUSE;
348-
}
349-
350-
conn = conn_get_unused();
351-
if (!conn) {
352-
NET_ERR("Not enough connection contexts. "
353-
"Consider increasing CONFIG_NET_MAX_CONN.");
354-
return -ENOENT;
355-
}
329+
NET_DBG("[%zu] connection handler %p changed local",
330+
conn - conns, conn);
356331

357-
if (local_addr) {
332+
if (local_addr != NULL) {
358333
if (IS_ENABLED(CONFIG_NET_IPV6) &&
359334
local_addr->sa_family == AF_INET6) {
360335
memcpy(&conn->local_addr, local_addr,
361336
sizeof(struct sockaddr_in6));
362337

363338
if (!net_ipv6_is_addr_unspecified(
364-
&net_sin6(local_addr)->
365-
sin6_addr)) {
366-
flags |= NET_CONN_LOCAL_ADDR_SPEC;
339+
&net_sin6(local_addr)->sin6_addr)) {
340+
conn->flags |= NET_CONN_LOCAL_ADDR_SPEC;
367341
}
368342
} else if (IS_ENABLED(CONFIG_NET_IPV4) &&
369343
local_addr->sa_family == AF_INET) {
370344
memcpy(&conn->local_addr, local_addr,
371345
sizeof(struct sockaddr_in));
372346

373347
if (net_sin(local_addr)->sin_addr.s_addr) {
374-
flags |= NET_CONN_LOCAL_ADDR_SPEC;
348+
conn->flags |= NET_CONN_LOCAL_ADDR_SPEC;
375349
}
376350
} else if (IS_ENABLED(CONFIG_NET_SOCKETS_CAN) &&
377351
local_addr->sa_family == AF_CAN) {
@@ -383,10 +357,54 @@ int net_conn_register(uint16_t proto, enum net_sock_type type, uint8_t family,
383357
sizeof(struct sockaddr_ll));
384358
} else {
385359
NET_ERR("Local address family not set");
386-
goto error;
360+
return -EINVAL;
387361
}
388362

389-
flags |= NET_CONN_LOCAL_ADDR_SET;
363+
conn->flags |= NET_CONN_LOCAL_ADDR_SET;
364+
} else {
365+
conn->flags &= ~NET_CONN_LOCAL_ADDR_SPEC;
366+
conn->flags &= ~NET_CONN_LOCAL_ADDR_SET;
367+
}
368+
369+
if (local_port > 0U) {
370+
conn->flags |= NET_CONN_LOCAL_PORT_SPEC;
371+
net_sin(&conn->local_addr)->sin_port = htons(local_port);
372+
} else {
373+
conn->flags &= ~NET_CONN_LOCAL_PORT_SPEC;
374+
}
375+
376+
return 0;
377+
}
378+
379+
int net_conn_register(uint16_t proto, enum net_sock_type type, uint8_t family,
380+
const struct sockaddr *remote_addr,
381+
const struct sockaddr *local_addr,
382+
uint16_t remote_port,
383+
uint16_t local_port,
384+
struct net_context *context,
385+
net_conn_cb_t cb,
386+
void *user_data,
387+
struct net_conn_handle **handle)
388+
{
389+
struct net_conn *conn;
390+
int ret;
391+
392+
conn = conn_find_handler(context != NULL ? net_context_get_iface(context) : NULL,
393+
proto, family, remote_addr, local_addr,
394+
remote_port, local_port,
395+
context != NULL ?
396+
net_context_is_reuseport_set(context) :
397+
false);
398+
if (conn != NULL) {
399+
NET_ERR("Identical connection handler %p already found.", conn);
400+
return -EADDRINUSE;
401+
}
402+
403+
conn = conn_get_unused();
404+
if (conn == NULL) {
405+
NET_ERR("Not enough connection contexts. "
406+
"Consider increasing CONFIG_NET_MAX_CONN.");
407+
return -ENOENT;
390408
}
391409

392410
if (remote_addr && local_addr) {
@@ -396,25 +414,20 @@ int net_conn_register(uint16_t proto, enum net_sock_type type, uint8_t family,
396414
}
397415
}
398416

399-
if (local_port) {
400-
flags |= NET_CONN_LOCAL_PORT_SPEC;
401-
net_sin(&conn->local_addr)->sin_port = htons(local_port);
402-
}
403-
404417
net_conn_change_callback(conn, cb, user_data);
405418

406-
conn->flags = flags;
407419
conn->proto = proto;
408420
conn->type = type;
409421
conn->family = family;
410422
conn->context = context;
411423

412-
/*
413-
* Since the net_conn_change_remote() updates the flags in connection,
414-
* must to be called after set the flags to connection.
415-
*/
424+
ret = net_conn_change_local(conn, local_addr, local_port);
425+
if (ret < 0) {
426+
goto error;
427+
}
428+
416429
ret = net_conn_change_remote(conn, remote_addr, remote_port);
417-
if (ret) {
430+
if (ret < 0) {
418431
goto error;
419432
}
420433

@@ -461,7 +474,9 @@ int net_conn_update(struct net_conn_handle *handle,
461474
net_conn_cb_t cb,
462475
void *user_data,
463476
const struct sockaddr *remote_addr,
464-
uint16_t remote_port)
477+
uint16_t remote_port,
478+
const struct sockaddr *local_addr,
479+
uint16_t local_port)
465480
{
466481
struct net_conn *conn = (struct net_conn *)handle;
467482
int ret;
@@ -476,6 +491,11 @@ int net_conn_update(struct net_conn_handle *handle,
476491

477492
net_conn_change_callback(conn, cb, user_data);
478493

494+
ret = net_conn_change_local(conn, local_addr, local_port);
495+
if (ret < 0) {
496+
return ret;
497+
}
498+
479499
ret = net_conn_change_remote(conn, remote_addr, remote_port);
480500

481501
return ret;

subsys/net/ip/connection.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,14 +170,18 @@ static inline int net_conn_unregister(struct net_conn_handle *handle)
170170
* @param user_data User data supplied by caller.
171171
* @param remote_addr Remote address
172172
* @param remote_port Remote port
173+
* @param local_addr Local address
174+
* @param local_port Local port
173175
*
174176
* @return Return 0 if the change succeed, <0 otherwise.
175177
*/
176178
int net_conn_update(struct net_conn_handle *handle,
177179
net_conn_cb_t cb,
178180
void *user_data,
179181
const struct sockaddr *remote_addr,
180-
uint16_t remote_port);
182+
uint16_t remote_port,
183+
const struct sockaddr *local_addr,
184+
uint16_t local_port);
181185

182186
/**
183187
* @brief Called by net_core.c when a network packet is received

subsys/net/ip/net_context.c

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2948,26 +2948,6 @@ static int recv_dgram(struct net_context *context,
29482948

29492949
ARG_UNUSED(timeout);
29502950

2951-
/* If the context already has a connection handler, it means it's
2952-
* already registered. In that case, all we have to do is 1) update
2953-
* the callback registered in the net_context and 2) update the
2954-
* user_data and remote address and port using net_conn_update().
2955-
*
2956-
* The callback function passed to net_conn_update() must be the same
2957-
* function as the one passed to net_conn_register(), not the callback
2958-
* set for the net context passed by recv_udp().
2959-
*/
2960-
if (context->conn_handler) {
2961-
context->recv_cb = cb;
2962-
ret = net_conn_update(context->conn_handler,
2963-
net_context_packet_received,
2964-
user_data,
2965-
context->flags & NET_CONTEXT_REMOTE_ADDR_SET ?
2966-
&context->remote : NULL,
2967-
ntohs(net_sin(&context->remote)->sin_port));
2968-
return ret;
2969-
}
2970-
29712951
ret = bind_default(context);
29722952
if (ret) {
29732953
return ret;
@@ -2999,6 +2979,26 @@ static int recv_dgram(struct net_context *context,
29992979

30002980
context->recv_cb = cb;
30012981

2982+
/* If the context already has a connection handler, it means it's
2983+
* already registered. In that case, all we have to do is 1) update
2984+
* the callback registered in the net_context and 2) update the
2985+
* user_data and local/remote address and port using net_conn_update().
2986+
*
2987+
* The callback function passed to net_conn_update() must be the same
2988+
* function as the one passed to net_conn_register(), not the callback
2989+
* set for the net context passed by recv_udp().
2990+
*/
2991+
if (context->conn_handler != NULL) {
2992+
ret = net_conn_update(context->conn_handler,
2993+
net_context_packet_received,
2994+
user_data,
2995+
context->flags & NET_CONTEXT_REMOTE_ADDR_SET ?
2996+
&context->remote : NULL,
2997+
ntohs(net_sin(&context->remote)->sin_port),
2998+
laddr, ntohs(lport));
2999+
return ret;
3000+
}
3001+
30023002
ret = net_conn_register(net_context_get_proto(context),
30033003
net_context_get_type(context),
30043004
net_context_get_family(context),
@@ -3060,10 +3060,17 @@ static int recv_raw(struct net_context *context,
30603060

30613061
ARG_UNUSED(timeout);
30623062

3063+
ret = bind_default(context);
3064+
if (ret) {
3065+
return ret;
3066+
}
3067+
3068+
context->recv_cb = cb;
3069+
30633070
/* If the context already has a connection handler, it means it's
30643071
* already registered. In that case, all we have to do is 1) update
30653072
* the callback registered in the net_context and 2) update the
3066-
* user_data using net_conn_update().
3073+
* user_data and local address using net_conn_update().
30673074
*
30683075
* The callback function passed to net_conn_update() must be the same
30693076
* function as the one passed to net_conn_register(), not the callback
@@ -3074,17 +3081,10 @@ static int recv_raw(struct net_context *context,
30743081
ret = net_conn_update(context->conn_handler,
30753082
net_context_raw_packet_received,
30763083
user_data,
3077-
NULL, 0);
3078-
return ret;
3079-
}
3080-
3081-
ret = bind_default(context);
3082-
if (ret) {
3084+
NULL, 0, local_addr, 0);
30833085
return ret;
30843086
}
30853087

3086-
context->recv_cb = cb;
3087-
30883088
ret = net_conn_register(net_context_get_proto(context),
30893089
net_context_get_type(context),
30903090
net_context_get_family(context),
@@ -3137,7 +3137,7 @@ int net_context_recv(struct net_context *context,
31373137
} else {
31383138
if (IS_ENABLED(CONFIG_NET_SOCKETS_PACKET) &&
31393139
family == AF_PACKET) {
3140-
struct sockaddr_ll addr;
3140+
struct sockaddr_ll addr = { 0 };
31413141

31423142
addr.sll_family = AF_PACKET;
31433143
addr.sll_ifindex =

0 commit comments

Comments
 (0)