Skip to content
Permalink
Browse files

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 <jukka.rissanen@linux.intel.com>
  • Loading branch information...
jukkar committed Jun 18, 2019
1 parent 7e37fd7 commit 06b500b6bd359144d6735decaf681caab408e07a
@@ -80,6 +80,7 @@ static inline int socket_can_setsockopt(struct device *dev, void *obj,
const void *optval, socklen_t optlen)
{
struct socket_can_context *socket_context = dev->driver_data;
struct net_context *ctx = obj;
int ret;

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

net_context_set_filter_id(ctx, ret);

return 0;
}

static inline void socket_can_close(struct device *dev, int filter_id)
{
struct socket_can_context *socket_context = dev->driver_data;

can_detach(socket_context->can_dev, filter_id);
}

static struct canbus_api socket_can_api = {
.iface_api.init = socket_can_iface_init,
.send = socket_can_send,
.close = socket_can_close,
.setsockopt = socket_can_setsockopt,
};

@@ -274,6 +274,10 @@ struct net_context {
void *offload_context;
#endif /* CONFIG_NET_OFFLOAD */

#if defined(CONFIG_NET_SOCKETS_CAN)
int can_filter_id;
#endif /* CONFIG_NET_SOCKETS_CAN */

/** Option values */
struct {
#if defined(CONFIG_NET_CONTEXT_PRIORITY)
@@ -432,6 +436,56 @@ static inline void net_context_set_type(struct net_context *context,
context->flags |= flag;
}

/**
* @brief Set CAN filter id for this network context.
*
* @details This function sets the CAN filter id of the context.
*
* @param context Network context.
* @param filter_id CAN filter id
*/
#if defined(CONFIG_NET_SOCKETS_CAN)
static inline void net_context_set_filter_id(struct net_context *context,
int filter_id)
{
NET_ASSERT(context);

context->can_filter_id = filter_id;
}
#else
static inline void net_context_set_filter_id(struct net_context *context,
int filter_id)
{
ARG_UNUSED(context);
ARG_UNUSED(filter_id);
}
#endif

/**
* @brief Get CAN filter id for this network context.
*
* @details This function gets the CAN filter id of the context.
*
* @param context Network context.
*
* @return Filter id of this network context
*/
#if defined(CONFIG_NET_SOCKETS_CAN)
static inline int net_context_get_filter_id(struct net_context *context)
{
NET_ASSERT(context);

return context->can_filter_id;
}
#else
static inline int net_context_get_filter_id(struct net_context *context)
{
ARG_UNUSED(context);

return -1;
}
#endif

/**
* @brief Get context IP protocol for this network context.
*
@@ -65,6 +65,9 @@ struct canbus_api {
/** Send a CAN packet by socket */
int (*send)(struct device *dev, struct net_pkt *pkt);

/** Close the related CAN socket */
void (*close)(struct device *dev, int filter_id);

/** Set socket CAN option */
int (*setsockopt)(struct device *dev, void *obj, int level, int optname,
const void *optval, socklen_t optlen);
@@ -330,7 +330,8 @@ int net_context_unref(struct net_context *context)
net_tcp_unref(context);

if (context->conn_handler) {
if (IS_ENABLED(CONFIG_NET_TCP) || IS_ENABLED(CONFIG_NET_UDP)) {
if (IS_ENABLED(CONFIG_NET_TCP) || IS_ENABLED(CONFIG_NET_UDP) ||
IS_ENABLED(CONFIG_NET_SOCKETS_CAN)) {
net_conn_unregister(context->conn_handler);
}

@@ -102,7 +102,8 @@ static void zcan_received_cb(struct net_context *ctx, struct net_pkt *pkt,
(struct zcan_frame *)net_pkt_data(pkt);
struct can_frame frame;

if (receivers[i].iface != net_pkt_iface(pkt)) {
if (!receivers[i].ctx ||
receivers[i].iface != net_pkt_iface(pkt)) {
continue;
}

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

static bool is_already_attached(struct can_filter *filter,
struct net_if *iface,
struct net_context *ctx)
{
int i;

for (i = 0; i < ARRAY_SIZE(receivers); i++) {
if (receivers[i].ctx != ctx && receivers[i].iface == iface &&
((receivers[i].can_id & receivers[i].can_mask) ==
(UNALIGNED_GET(&filter->can_id) &
UNALIGNED_GET(&filter->can_mask)))) {
return true;
}
}

return false;
}

static int close_socket(struct net_context *ctx)
{
const struct canbus_api *api;
struct net_if *iface;
struct device *dev;

iface = net_context_get_iface(ctx);
dev = net_if_get_device(iface);
api = dev->driver_api;

if (!api || !api->close) {
return -ENOTSUP;
}

api->close(dev, net_context_get_filter_id(ctx));

return 0;
}

static int can_close_socket(struct net_context *ctx)
{
int i, ret;

for (i = 0; i < ARRAY_SIZE(receivers); i++) {
if (receivers[i].ctx == ctx) {
struct can_filter filter;

receivers[i].ctx = NULL;

filter.can_id = receivers[i].can_id;
filter.can_mask = receivers[i].can_mask;

if (!is_already_attached(&filter,
net_context_get_iface(ctx),
ctx)) {
/* We can detach now as there are no other
* sockets that have same filter.
*/
ret = close_socket(ctx);
if (ret < 0) {
return ret;
}
}

return 0;
}
}

return 0;
}

static int can_sock_ioctl_vmeth(void *obj, unsigned int request, va_list args)
{
if (request == ZFD_IOCTL_CLOSE) {
int ret;

ret = can_close_socket(obj);
if (ret < 0) {
NET_DBG("Cannot detach net_context %p (%d)", obj, ret);
}
}

return sock_fd_op_vtable.fd_vtable.ioctl(obj, request, args);
}

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

static bool is_already_attached(struct can_filter *filter,
struct net_if *iface,
struct net_context *ctx)
{
int i;

for (i = 0; i < ARRAY_SIZE(receivers); i++) {
if (receivers[i].ctx != ctx && receivers[i].iface == iface &&
((receivers[i].can_id & receivers[i].can_mask) ==
(UNALIGNED_GET(&filter->can_id) &
UNALIGNED_GET(&filter->can_mask)))) {
return true;
}
}

return false;
}

static int can_sock_setsockopt_vmeth(void *obj, int level, int optname,
const void *optval, socklen_t optlen)
{

0 comments on commit 06b500b

Please sign in to comment.
You can’t perform that action at this time.