Skip to content

Commit 6621491

Browse files
committed
net: sockets: can: Add dispatcher
We need to dispatch the received CAN frame if there are multiple sockets interested in the same CAN-IDs. Signed-off-by: Jukka Rissanen <[email protected]>
1 parent 67f0550 commit 6621491

File tree

3 files changed

+267
-50
lines changed

3 files changed

+267
-50
lines changed

subsys/net/ip/net_context.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1708,6 +1708,13 @@ int net_context_recv(struct net_context *context,
17081708
} else if (IS_ENABLED(CONFIG_NET_SOCKETS_CAN) &&
17091709
net_context_get_family(context) == AF_CAN) {
17101710
ret = recv_raw(context, cb, timeout, user_data);
1711+
if (ret == -EALREADY) {
1712+
/* This is perfectly normal for CAN sockets.
1713+
* The SocketCAN will dispatch the packet to
1714+
* correct net_context listener.
1715+
*/
1716+
ret = 0;
1717+
}
17111718
} else {
17121719
ret = -EPROTOTYPE;
17131720
}

subsys/net/lib/sockets/Kconfig

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,14 @@ config NET_SOCKETS_CAN
124124
help
125125
The value depends on your network needs.
126126

127+
config NET_SOCKETS_CAN_RECEIVERS
128+
int "How many simultaneous SocketCAN receivers are allowed"
129+
default 1
130+
depends on NET_SOCKETS_CAN
131+
help
132+
The value tells how many sockets can receive data from same
133+
Socket-CAN interface.
134+
127135
module = NET_SOCKETS
128136
module-dep = NET_LOG
129137
module-str = Log level for BSD sockets compatible API calls

subsys/net/lib/sockets/sockets_can.c

Lines changed: 252 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,17 @@ LOG_MODULE_REGISTER(net_sock_can, CONFIG_NET_SOCKETS_LOG_LEVEL);
2222

2323
#include "sockets_internal.h"
2424

25+
#define MEM_ALLOC_TIMEOUT K_MSEC(50)
26+
27+
struct can_recv {
28+
struct net_if *iface;
29+
struct net_context *ctx;
30+
canid_t can_id;
31+
canid_t can_mask;
32+
};
33+
34+
static struct can_recv receivers[CONFIG_NET_SOCKETS_CAN_RECEIVERS];
35+
2536
extern const struct socket_op_vtable sock_fd_op_vtable;
2637

2738
static const struct socket_op_vtable can_sock_fd_op_vtable;
@@ -77,32 +88,87 @@ static void zcan_received_cb(struct net_context *ctx, struct net_pkt *pkt,
7788
union net_proto_header *proto_hdr,
7889
int status, void *user_data)
7990
{
80-
NET_DBG("ctx %p pkt %p st %d ud %p", ctx, pkt, status, user_data);
91+
/* The ctx parameter is not really relevant here. It refers to first
92+
* net_context that was used when registering CAN socket.
93+
* In practice there can be multiple sockets that are interested in
94+
* same CAN id packets. That is why we need to implement the dispatcher
95+
* which will give the packet to correct net_context(s).
96+
*/
97+
struct net_pkt *clone = NULL;
98+
int i;
8199

82-
/* if pkt is NULL, EOF */
83-
if (!pkt) {
84-
struct net_pkt *last_pkt = k_fifo_peek_tail(&ctx->recv_q);
100+
for (i = 0; i < ARRAY_SIZE(receivers); i++) {
101+
struct zcan_frame *zframe =
102+
(struct zcan_frame *)net_pkt_data(pkt);
103+
struct can_frame frame;
104+
105+
if (receivers[i].iface != net_pkt_iface(pkt)) {
106+
continue;
107+
}
108+
109+
can_copy_zframe_to_frame(zframe, &frame);
85110

86-
if (!last_pkt) {
87-
/* If there're no packets in the queue, recv() may
88-
* be blocked waiting on it to become non-empty,
89-
* so cancel that wait.
111+
if ((frame.can_id & receivers[i].can_mask) !=
112+
(receivers[i].can_id & receivers[i].can_mask)) {
113+
continue;
114+
}
115+
116+
/* If there are multiple receivers configured, we use the
117+
* original net_pkt as a template, and just clone it to all
118+
* recipients. This is done like this so that we avoid the
119+
* original net_pkt being freed while we are cloning it.
120+
*/
121+
if (pkt != NULL && ARRAY_SIZE(receivers) > 1) {
122+
/* There are multiple receivers, we need to clone
123+
* the packet.
90124
*/
91-
sock_set_eof(ctx);
92-
k_fifo_cancel_wait(&ctx->recv_q);
93-
NET_DBG("Marked socket %p as peer-closed", ctx);
125+
clone = net_pkt_clone(pkt, MEM_ALLOC_TIMEOUT);
126+
if (!clone) {
127+
/* Sent the packet to at least one recipient
128+
* if there is no memory to clone the packet.
129+
*/
130+
clone = pkt;
131+
}
94132
} else {
95-
net_pkt_set_eof(last_pkt, true);
96-
NET_DBG("Set EOF flag on pkt %p", ctx);
133+
clone = pkt;
97134
}
98135

99-
return;
100-
}
136+
ctx = receivers[i].ctx;
137+
138+
NET_DBG("[%d] ctx %p pkt %p st %d", i, ctx, clone, status);
139+
140+
/* if pkt is NULL, EOF */
141+
if (!clone) {
142+
struct net_pkt *last_pkt =
143+
k_fifo_peek_tail(&ctx->recv_q);
144+
145+
if (!last_pkt) {
146+
/* If there're no packets in the queue,
147+
* recv() may be blocked waiting on it to
148+
* become non-empty, so cancel that wait.
149+
*/
150+
sock_set_eof(ctx);
151+
k_fifo_cancel_wait(&ctx->recv_q);
152+
153+
NET_DBG("Marked socket %p as peer-closed", ctx);
154+
} else {
155+
net_pkt_set_eof(last_pkt, true);
156+
157+
NET_DBG("Set EOF flag on pkt %p", ctx);
158+
}
159+
160+
return;
161+
} else {
162+
/* Normal packet */
163+
net_pkt_set_eof(clone, false);
101164

102-
/* Normal packet */
103-
net_pkt_set_eof(pkt, false);
165+
k_fifo_put(&ctx->recv_q, clone);
166+
}
167+
}
104168

105-
k_fifo_put(&ctx->recv_q, pkt);
169+
if (clone && clone != pkt) {
170+
net_pkt_unref(pkt);
171+
}
106172
}
107173

108174
static int zcan_bind_ctx(struct net_context *ctx, const struct sockaddr *addr,
@@ -232,20 +298,18 @@ static ssize_t zcan_recvfrom_ctx(struct net_context *ctx, void *buf,
232298
}
233299

234300
if (net_pkt_read(pkt, (void *)&zframe, sizeof(zframe))) {
301+
net_pkt_unref(pkt);
302+
235303
errno = EIO;
236304
return -1;
237305
}
238306

239-
if (!(flags & ZSOCK_MSG_PEEK)) {
240-
net_pkt_unref(pkt);
241-
} else {
242-
net_pkt_cursor_init(pkt);
243-
}
244-
245307
NET_ASSERT(recv_len == sizeof(struct can_frame));
246308

247309
can_copy_zframe_to_frame(&zframe, (struct can_frame *)buf);
248310

311+
net_pkt_unref(pkt);
312+
249313
return recv_len;
250314
}
251315

@@ -361,52 +425,190 @@ static int can_sock_getsockopt_vmeth(void *obj, int level, int optname,
361425
return zcan_getsockopt_ctx(obj, level, optname, optval, optlen);
362426
}
363427

428+
static int can_register_receiver(struct net_if *iface, struct net_context *ctx,
429+
canid_t can_id, canid_t can_mask)
430+
{
431+
int i;
432+
433+
NET_DBG("Max %lu receivers", ARRAY_SIZE(receivers));
434+
435+
for (i = 0; i < ARRAY_SIZE(receivers); i++) {
436+
if (receivers[i].ctx != NULL) {
437+
continue;
438+
}
439+
440+
receivers[i].ctx = ctx;
441+
receivers[i].iface = iface;
442+
receivers[i].can_id = can_id;
443+
receivers[i].can_mask = can_mask;
444+
445+
return i;
446+
}
447+
448+
return -ENOENT;
449+
}
450+
451+
static void can_unregister_receiver(struct net_if *iface,
452+
struct net_context *ctx,
453+
canid_t can_id, canid_t can_mask)
454+
{
455+
int i;
456+
457+
for (i = 0; i < ARRAY_SIZE(receivers); i++) {
458+
if (receivers[i].ctx == ctx &&
459+
receivers[i].iface == iface &&
460+
receivers[i].can_id == can_id &&
461+
receivers[i].can_mask == can_mask) {
462+
receivers[i].ctx = NULL;
463+
return;
464+
}
465+
}
466+
}
467+
468+
static int can_register_filters(struct net_if *iface, struct net_context *ctx,
469+
const struct can_filter *filters, int count)
470+
{
471+
int i, ret;
472+
473+
NET_DBG("Registering %d filters", count);
474+
475+
for (i = 0; i < count; i++) {
476+
ret = can_register_receiver(iface, ctx, filters[i].can_id,
477+
filters[i].can_mask);
478+
if (ret < 0) {
479+
goto revert;
480+
}
481+
}
482+
483+
return 0;
484+
485+
revert:
486+
for (i = 0; i < count; i++) {
487+
can_unregister_receiver(iface, ctx, filters[i].can_id,
488+
filters[i].can_mask);
489+
}
490+
491+
return ret;
492+
}
493+
494+
static void can_unregister_filters(struct net_if *iface,
495+
struct net_context *ctx,
496+
const struct can_filter *filters,
497+
int count)
498+
{
499+
int i;
500+
501+
NET_DBG("Unregistering %d filters", count);
502+
503+
for (i = 0; i < count; i++) {
504+
can_unregister_receiver(iface, ctx, filters[i].can_id,
505+
filters[i].can_mask);
506+
}
507+
}
508+
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+
364527
static int can_sock_setsockopt_vmeth(void *obj, int level, int optname,
365528
const void *optval, socklen_t optlen)
366529
{
367-
if (level == SOL_CAN_RAW) {
368-
const struct canbus_api *api;
369-
struct net_if *iface;
370-
struct device *dev;
530+
const struct canbus_api *api;
531+
struct net_if *iface;
532+
struct device *dev;
533+
int ret;
371534

372-
/* The application must use can_filter and then we convert
373-
* it to zcan_filter as the CANBUS drivers expects that.
374-
*/
375-
if (optname == CAN_RAW_FILTER &&
376-
optlen != sizeof(struct can_filter)) {
377-
errno = EINVAL;
378-
return -1;
379-
}
535+
if (level != SOL_CAN_RAW) {
536+
return zcan_setsockopt_ctx(obj, level, optname, optval, optlen);
537+
}
380538

381-
if (optval == NULL) {
539+
/* The application must use CAN_filter and then we convert
540+
* it to zcan_filter as the CANBUS drivers expects that.
541+
*/
542+
if (optname == CAN_RAW_FILTER && optlen != sizeof(struct can_filter)) {
543+
errno = EINVAL;
544+
return -1;
545+
}
546+
547+
if (optval == NULL) {
548+
errno = EINVAL;
549+
return -1;
550+
}
551+
552+
iface = net_context_get_iface(obj);
553+
dev = net_if_get_device(iface);
554+
api = dev->driver_api;
555+
556+
if (!api || !api->setsockopt) {
557+
errno = ENOTSUP;
558+
return -1;
559+
}
560+
561+
if (optname == CAN_RAW_FILTER) {
562+
int count, i;
563+
564+
if (optlen % sizeof(struct can_filter) != 0) {
382565
errno = EINVAL;
383566
return -1;
384567
}
385568

386-
iface = net_context_get_iface(obj);
387-
dev = net_if_get_device(iface);
388-
api = dev->driver_api;
569+
count = optlen / sizeof(struct can_filter);
389570

390-
if (!api || !api->setsockopt) {
391-
errno = ENOTSUP;
571+
ret = can_register_filters(iface, obj, optval, count);
572+
if (ret < 0) {
573+
errno = -ret;
392574
return -1;
393575
}
394576

395-
if (optname == CAN_RAW_FILTER) {
577+
for (i = 0; i < count; i++) {
578+
struct can_filter *filter;
396579
struct zcan_filter zfilter;
580+
bool duplicate;
397581

398-
can_copy_filter_to_zfilter((struct can_filter *)optval,
399-
&zfilter);
582+
filter = &((struct can_filter *)optval)[i];
400583

401-
return api->setsockopt(dev, obj, level, optname,
402-
&zfilter, sizeof(zfilter));
584+
/* If someone has already attached the same filter to
585+
* same interface, we do not need to do it here again.
586+
*/
587+
duplicate = is_already_attached(filter, iface, obj);
588+
if (duplicate) {
589+
continue;
590+
}
591+
592+
can_copy_filter_to_zfilter(filter, &zfilter);
593+
594+
ret = api->setsockopt(dev, obj, level, optname,
595+
&zfilter, sizeof(zfilter));
596+
if (ret < 0) {
597+
break;
598+
}
599+
}
600+
601+
if (ret < 0) {
602+
can_unregister_filters(iface, obj, optval, count);
603+
604+
errno = -ret;
605+
return -1;
403606
}
404607

405-
return api->setsockopt(dev, obj, level, optname,
406-
optval, optlen);
608+
return 0;
407609
}
408610

409-
return zcan_setsockopt_ctx(obj, level, optname, optval, optlen);
611+
return api->setsockopt(dev, obj, level, optname, optval, optlen);
410612
}
411613

412614
static const struct socket_op_vtable can_sock_fd_op_vtable = {

0 commit comments

Comments
 (0)