Skip to content

Commit 06b500b

Browse files
committed
net: sockets: can: Close the socket cleanly
If the socket is closed, then do CAN detach if that is needed. This way the CAN interrupts are not received if there are no CAN sockets listening the data. Signed-off-by: Jukka Rissanen <[email protected]>
1 parent 7e37fd7 commit 06b500b

File tree

5 files changed

+150
-20
lines changed

5 files changed

+150
-20
lines changed

drivers/can/socket_can_generic.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ static inline int socket_can_setsockopt(struct device *dev, void *obj,
8080
const void *optval, socklen_t optlen)
8181
{
8282
struct socket_can_context *socket_context = dev->driver_data;
83+
struct net_context *ctx = obj;
8384
int ret;
8485

8586
if (level != SOL_CAN_RAW && optname != CAN_RAW_FILTER) {
@@ -96,12 +97,22 @@ static inline int socket_can_setsockopt(struct device *dev, void *obj,
9697
return -1;
9798
}
9899

100+
net_context_set_filter_id(ctx, ret);
101+
99102
return 0;
100103
}
101104

105+
static inline void socket_can_close(struct device *dev, int filter_id)
106+
{
107+
struct socket_can_context *socket_context = dev->driver_data;
108+
109+
can_detach(socket_context->can_dev, filter_id);
110+
}
111+
102112
static struct canbus_api socket_can_api = {
103113
.iface_api.init = socket_can_iface_init,
104114
.send = socket_can_send,
115+
.close = socket_can_close,
105116
.setsockopt = socket_can_setsockopt,
106117
};
107118

include/net/net_context.h

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,10 @@ struct net_context {
274274
void *offload_context;
275275
#endif /* CONFIG_NET_OFFLOAD */
276276

277+
#if defined(CONFIG_NET_SOCKETS_CAN)
278+
int can_filter_id;
279+
#endif /* CONFIG_NET_SOCKETS_CAN */
280+
277281
/** Option values */
278282
struct {
279283
#if defined(CONFIG_NET_CONTEXT_PRIORITY)
@@ -432,6 +436,56 @@ static inline void net_context_set_type(struct net_context *context,
432436
context->flags |= flag;
433437
}
434438

439+
/**
440+
* @brief Set CAN filter id for this network context.
441+
*
442+
* @details This function sets the CAN filter id of the context.
443+
*
444+
* @param context Network context.
445+
* @param filter_id CAN filter id
446+
*/
447+
#if defined(CONFIG_NET_SOCKETS_CAN)
448+
static inline void net_context_set_filter_id(struct net_context *context,
449+
int filter_id)
450+
{
451+
NET_ASSERT(context);
452+
453+
context->can_filter_id = filter_id;
454+
}
455+
#else
456+
static inline void net_context_set_filter_id(struct net_context *context,
457+
int filter_id)
458+
{
459+
ARG_UNUSED(context);
460+
ARG_UNUSED(filter_id);
461+
}
462+
#endif
463+
464+
/**
465+
* @brief Get CAN filter id for this network context.
466+
*
467+
* @details This function gets the CAN filter id of the context.
468+
*
469+
* @param context Network context.
470+
*
471+
* @return Filter id of this network context
472+
*/
473+
#if defined(CONFIG_NET_SOCKETS_CAN)
474+
static inline int net_context_get_filter_id(struct net_context *context)
475+
{
476+
NET_ASSERT(context);
477+
478+
return context->can_filter_id;
479+
}
480+
#else
481+
static inline int net_context_get_filter_id(struct net_context *context)
482+
{
483+
ARG_UNUSED(context);
484+
485+
return -1;
486+
}
487+
#endif
488+
435489
/**
436490
* @brief Get context IP protocol for this network context.
437491
*

include/net/socket_can.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ struct canbus_api {
6565
/** Send a CAN packet by socket */
6666
int (*send)(struct device *dev, struct net_pkt *pkt);
6767

68+
/** Close the related CAN socket */
69+
void (*close)(struct device *dev, int filter_id);
70+
6871
/** Set socket CAN option */
6972
int (*setsockopt)(struct device *dev, void *obj, int level, int optname,
7073
const void *optval, socklen_t optlen);

subsys/net/ip/net_context.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,8 @@ int net_context_unref(struct net_context *context)
330330
net_tcp_unref(context);
331331

332332
if (context->conn_handler) {
333-
if (IS_ENABLED(CONFIG_NET_TCP) || IS_ENABLED(CONFIG_NET_UDP)) {
333+
if (IS_ENABLED(CONFIG_NET_TCP) || IS_ENABLED(CONFIG_NET_UDP) ||
334+
IS_ENABLED(CONFIG_NET_SOCKETS_CAN)) {
334335
net_conn_unregister(context->conn_handler);
335336
}
336337

subsys/net/lib/sockets/sockets_can.c

Lines changed: 80 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,8 @@ static void zcan_received_cb(struct net_context *ctx, struct net_pkt *pkt,
102102
(struct zcan_frame *)net_pkt_data(pkt);
103103
struct can_frame frame;
104104

105-
if (receivers[i].iface != net_pkt_iface(pkt)) {
105+
if (!receivers[i].ctx ||
106+
receivers[i].iface != net_pkt_iface(pkt)) {
106107
continue;
107108
}
108109

@@ -343,8 +344,86 @@ static ssize_t can_sock_write_vmeth(void *obj, const void *buffer,
343344
return zcan_sendto_ctx(obj, buffer, count, 0, NULL, 0);
344345
}
345346

347+
static bool is_already_attached(struct can_filter *filter,
348+
struct net_if *iface,
349+
struct net_context *ctx)
350+
{
351+
int i;
352+
353+
for (i = 0; i < ARRAY_SIZE(receivers); i++) {
354+
if (receivers[i].ctx != ctx && receivers[i].iface == iface &&
355+
((receivers[i].can_id & receivers[i].can_mask) ==
356+
(UNALIGNED_GET(&filter->can_id) &
357+
UNALIGNED_GET(&filter->can_mask)))) {
358+
return true;
359+
}
360+
}
361+
362+
return false;
363+
}
364+
365+
static int close_socket(struct net_context *ctx)
366+
{
367+
const struct canbus_api *api;
368+
struct net_if *iface;
369+
struct device *dev;
370+
371+
iface = net_context_get_iface(ctx);
372+
dev = net_if_get_device(iface);
373+
api = dev->driver_api;
374+
375+
if (!api || !api->close) {
376+
return -ENOTSUP;
377+
}
378+
379+
api->close(dev, net_context_get_filter_id(ctx));
380+
381+
return 0;
382+
}
383+
384+
static int can_close_socket(struct net_context *ctx)
385+
{
386+
int i, ret;
387+
388+
for (i = 0; i < ARRAY_SIZE(receivers); i++) {
389+
if (receivers[i].ctx == ctx) {
390+
struct can_filter filter;
391+
392+
receivers[i].ctx = NULL;
393+
394+
filter.can_id = receivers[i].can_id;
395+
filter.can_mask = receivers[i].can_mask;
396+
397+
if (!is_already_attached(&filter,
398+
net_context_get_iface(ctx),
399+
ctx)) {
400+
/* We can detach now as there are no other
401+
* sockets that have same filter.
402+
*/
403+
ret = close_socket(ctx);
404+
if (ret < 0) {
405+
return ret;
406+
}
407+
}
408+
409+
return 0;
410+
}
411+
}
412+
413+
return 0;
414+
}
415+
346416
static int can_sock_ioctl_vmeth(void *obj, unsigned int request, va_list args)
347417
{
418+
if (request == ZFD_IOCTL_CLOSE) {
419+
int ret;
420+
421+
ret = can_close_socket(obj);
422+
if (ret < 0) {
423+
NET_DBG("Cannot detach net_context %p (%d)", obj, ret);
424+
}
425+
}
426+
348427
return sock_fd_op_vtable.fd_vtable.ioctl(obj, request, args);
349428
}
350429

@@ -506,24 +585,6 @@ static void can_unregister_filters(struct net_if *iface,
506585
}
507586
}
508587

509-
static bool is_already_attached(struct can_filter *filter,
510-
struct net_if *iface,
511-
struct net_context *ctx)
512-
{
513-
int i;
514-
515-
for (i = 0; i < ARRAY_SIZE(receivers); i++) {
516-
if (receivers[i].ctx != ctx && receivers[i].iface == iface &&
517-
((receivers[i].can_id & receivers[i].can_mask) ==
518-
(UNALIGNED_GET(&filter->can_id) &
519-
UNALIGNED_GET(&filter->can_mask)))) {
520-
return true;
521-
}
522-
}
523-
524-
return false;
525-
}
526-
527588
static int can_sock_setsockopt_vmeth(void *obj, int level, int optname,
528589
const void *optval, socklen_t optlen)
529590
{

0 commit comments

Comments
 (0)