On 30.11.21 09:33, Jan Kiszka via Xenomai wrote:
> On 29.11.21 23:07, Dario Binacchi wrote:
>> The `user_msghdr' structure is designed to send multiple messages as
>> well, so rtcan_raw_sendmsg() can also send multiple messages. This
>> avoids having to add the sendmmsg system call which requires more
>> extensive Xenomai changes.
>>
>> Signed-off-by: Dario Binacchi <dario...@libero.it>
>> ---
>>
>> (no changes since v1)
>>
> 
> I asked for testing the changes also smokey (via rtcan_virt). How about
> that?
> 

Adding C Smith: There is also the series that fixes compat support for
RTCAN [1], switching to rtdm helper to access iov structs. Please align
your activities so that we get the best of all.

And I can only stress my point above that we need at least basic testing
for CAN along this.

Thanks,
Jan

[1] https://xenomai.org/pipermail/xenomai/2021-November/046722.html

> Jan
> 
>>  kernel/drivers/can/rtcan_raw.c | 239 ++++++++++++++++++---------------
>>  1 file changed, 128 insertions(+), 111 deletions(-)
>>
>> diff --git a/kernel/drivers/can/rtcan_raw.c b/kernel/drivers/can/rtcan_raw.c
>> index 693b927fe..b17c1709d 100644
>> --- a/kernel/drivers/can/rtcan_raw.c
>> +++ b/kernel/drivers/can/rtcan_raw.c
>> @@ -762,113 +762,13 @@ ssize_t rtcan_raw_recvmsg(struct rtdm_fd *fd,
>>  }
>>  
>>  
>> -ssize_t rtcan_raw_sendmsg(struct rtdm_fd *fd,
>> -                      const struct user_msghdr *msg, int flags)
>> +static ssize_t __rtcan_raw_sendmsg(struct rtcan_device *dev, struct 
>> rtcan_socket *sock,
>> +                               can_frame_t *frame, nanosecs_rel_t timeout)
>>  {
>> -    struct rtcan_socket *sock = rtdm_fd_to_private(fd);
>> -    struct sockaddr_can *scan = (struct sockaddr_can *)msg->msg_name;
>> -    struct sockaddr_can scan_buf;
>> -    struct iovec *iov = (struct iovec *)msg->msg_iov;
>> -    struct iovec iov_buf;
>> -    can_frame_t *frame;
>> -    can_frame_t frame_buf;
>> -    rtdm_lockctx_t lock_ctx;
>> -    nanosecs_rel_t timeout = 0;
>>      struct tx_wait_queue tx_wait;
>> -    struct rtcan_device *dev;
>> -    int ifindex = 0;
>> -    int ret  = 0;
>> +    rtdm_lockctx_t lock_ctx;
>>      spl_t s;
>> -
>> -
>> -    if (flags & MSG_OOB)   /* Mirror BSD error message compatibility */
>> -    return -EOPNOTSUPP;
>> -
>> -    /* Only MSG_DONTWAIT is a valid flag. */
>> -    if (flags & ~MSG_DONTWAIT)
>> -    return -EINVAL;
>> -
>> -    /* Check msg_iovlen, only one buffer allowed */
>> -    if (msg->msg_iovlen != 1)
>> -    return -EMSGSIZE;
>> -
>> -    if (scan == NULL) {
>> -    /* No socket address. Will use bound interface for sending */
>> -
>> -    if (msg->msg_namelen != 0)
>> -        return -EINVAL;
>> -
>> -
>> -    /* We only want a consistent value here, a spin lock would be
>> -     * overkill. Nevertheless, the binding could change till we have
>> -     * the chance to send. Blame the user, though. */
>> -    ifindex = atomic_read(&sock->ifindex);
>> -
>> -    if (!ifindex)
>> -        /* Socket isn't bound or bound to all interfaces. Go out. */
>> -        return -ENXIO;
>> -    } else {
>> -    /* Socket address given */
>> -    if (msg->msg_namelen < sizeof(struct sockaddr_can))
>> -        return -EINVAL;
>> -
>> -    if (rtdm_fd_is_user(fd)) {
>> -        /* Copy socket address from userspace */
>> -        if (!rtdm_read_user_ok(fd, msg->msg_name,
>> -                               sizeof(struct sockaddr_can)) ||
>> -            rtdm_copy_from_user(fd, &scan_buf, msg->msg_name,
>> -                                sizeof(struct sockaddr_can)))
>> -            return -EFAULT;
>> -
>> -        scan = &scan_buf;
>> -    }
>> -
>> -    /* Check address family */
>> -    if (scan->can_family != AF_CAN)
>> -        return -EINVAL;
>> -
>> -    ifindex = scan->can_ifindex;
>> -    }
>> -
>> -    if (rtdm_fd_is_user(fd)) {
>> -    /* Copy IO vector from userspace */
>> -    if (!rtdm_rw_user_ok(fd, msg->msg_iov,
>> -                         sizeof(struct iovec)) ||
>> -        rtdm_copy_from_user(fd, &iov_buf, msg->msg_iov,
>> -                            sizeof(struct iovec)))
>> -        return -EFAULT;
>> -
>> -    iov = &iov_buf;
>> -    }
>> -
>> -    /* Check size of buffer */
>> -    if (iov->iov_len != sizeof(can_frame_t))
>> -    return -EMSGSIZE;
>> -
>> -    frame = (can_frame_t *)iov->iov_base;
>> -
>> -    if (rtdm_fd_is_user(fd)) {
>> -    /* Copy CAN frame from userspace */
>> -    if (!rtdm_read_user_ok(fd, iov->iov_base,
>> -                           sizeof(can_frame_t)) ||
>> -        rtdm_copy_from_user(fd, &frame_buf, iov->iov_base,
>> -                            sizeof(can_frame_t)))
>> -        return -EFAULT;
>> -
>> -    frame = &frame_buf;
>> -    }
>> -
>> -    /* Adjust iovec in the common way */
>> -    iov->iov_base += sizeof(can_frame_t);
>> -    iov->iov_len -= sizeof(can_frame_t);
>> -    /* ... and copy it back to userspace if necessary */
>> -    if (rtdm_fd_is_user(fd)) {
>> -    if (rtdm_copy_to_user(fd, msg->msg_iov, iov,
>> -                          sizeof(struct iovec)))
>> -        return -EFAULT;
>> -    }
>> -
>> -    /* At last, we've got the frame ... */
>> +    int ret = 0;
>>  
>>      /* Check if DLC between 0 and 15 */
>>      if (frame->can_dlc > 15)
>> @@ -881,11 +781,6 @@ ssize_t rtcan_raw_sendmsg(struct rtdm_fd *fd,
>>          return -EINVAL;
>>      }
>>  
>> -    if ((dev = rtcan_dev_get_by_index(ifindex)) == NULL)
>> -    return -ENXIO;
>> -
>> -    timeout = (flags & MSG_DONTWAIT) ? RTDM_TIMEOUT_NONE : sock->tx_timeout;
>> -
>>      tx_wait.rt_task = rtdm_task_current();
>>  
>>      /* Register the task at the socket's TX wait queue and decrement
>> @@ -931,7 +826,6 @@ ssize_t rtcan_raw_sendmsg(struct rtdm_fd *fd,
>>  
>>      /* We got access */
>>  
>> -
>>      /* Push message onto stack for loopback when TX done */
>>      if (rtcan_loopback_enabled(sock))
>>      rtcan_tx_push(dev, sock, frame);
>> @@ -960,10 +854,133 @@ ssize_t rtcan_raw_sendmsg(struct rtdm_fd *fd,
>>   send_out2:
>>      rtdm_lock_put_irqrestore(&dev->device_lock, lock_ctx);
>>   send_out1:
>> -    rtcan_dev_dereference(dev);
>>      return ret;
>>  }
>>  
>> +ssize_t rtcan_raw_sendmsg(struct rtdm_fd *fd,
>> +                      const struct user_msghdr *msg, int flags)
>> +{
>> +    struct rtcan_socket *sock = rtdm_fd_to_private(fd);
>> +    struct sockaddr_can *scan = (struct sockaddr_can *)msg->msg_name;
>> +    struct sockaddr_can scan_buf;
>> +    struct iovec *iov = (struct iovec *)msg->msg_iov;
>> +    struct iovec iov_buf;
>> +    can_frame_t *frame;
>> +    can_frame_t frame_buf;
>> +    nanosecs_rel_t timeout;
>> +    struct rtcan_device *dev;
>> +    int ret = 0, ifindex = 0, i = 0, n, sent = 0;
>> +
>> +    if (flags & MSG_OOB)   /* Mirror BSD error message compatibility */
>> +    return -EOPNOTSUPP;
>> +
>> +    /* Only MSG_DONTWAIT is a valid flag. */
>> +    if (flags & ~MSG_DONTWAIT)
>> +    return -EINVAL;
>> +
>> +    timeout = (flags & MSG_DONTWAIT) ? RTDM_TIMEOUT_NONE : sock->tx_timeout;
>> +
>> +    if (scan == NULL) {
>> +    /* No socket address. Will use bound interface for sending */
>> +    if (msg->msg_namelen != 0)
>> +        return -EINVAL;
>> +
>> +
>> +    /* We only want a consistent value here, a spin lock would be
>> +     * overkill. Nevertheless, the binding could change till we have
>> +     * the chance to send. Blame the user, though. */
>> +    ifindex = atomic_read(&sock->ifindex);
>> +    if (!ifindex)
>> +        /* Socket isn't bound or bound to all interfaces. Go out. */
>> +        return -ENXIO;
>> +    } else {
>> +    /* Socket address given */
>> +    if (msg->msg_namelen < sizeof(struct sockaddr_can))
>> +        return -EINVAL;
>> +
>> +    if (rtdm_fd_is_user(fd)) {
>> +        /* Copy socket address from userspace */
>> +        if (!rtdm_read_user_ok(fd, msg->msg_name,
>> +                               sizeof(struct sockaddr_can)) ||
>> +            rtdm_copy_from_user(fd, &scan_buf, msg->msg_name,
>> +                                sizeof(struct sockaddr_can)))
>> +            return -EFAULT;
>> +
>> +        scan = &scan_buf;
>> +    }
>> +
>> +    /* Check address family */
>> +    if (scan->can_family != AF_CAN)
>> +        return -EINVAL;
>> +
>> +    ifindex = scan->can_ifindex;
>> +    }
>> +
>> +    dev = rtcan_dev_get_by_index(ifindex);
>> +    if (!dev)
>> +    return -ENXIO;
>> +
>> +    if (rtdm_fd_is_user(fd)) {
>> +
>> +    /* Copy IO vector from userspace */
>> +    if (!rtdm_rw_user_ok(fd, msg->msg_iov,
>> +                         sizeof(struct iovec)) ||
>> +        rtdm_copy_from_user(fd, &iov_buf, msg->msg_iov,
>> +                            sizeof(struct iovec))) {
>> +        ret = -EFAULT;
>> +        goto finally;
>> +    }
>> +
>> +    iov = &iov_buf;
>> +    }
>> +
>> +    n = msg->msg_iovlen;
>> +    while (i < n) {
>> +    if (iov->iov_len < sizeof(can_frame_t)) {
>> +        ret = -EMSGSIZE;
>> +        goto finally;
>> +    }
>> +
>> +    frame = (can_frame_t *)iov->iov_base;
>> +
>> +    if (rtdm_fd_is_user(fd)) {
>> +        /* Copy CAN frame from userspace */
>> +        if (!rtdm_read_user_ok(fd, iov->iov_base, sizeof(can_frame_t)) ||
>> +            rtdm_copy_from_user(fd, &frame_buf, iov->iov_base,
>> +                                sizeof(can_frame_t))) {
>> +            ret = -EFAULT;
>> +            goto finally;
>> +        }
>> +
>> +        frame = &frame_buf;
>> +    }
>> +
>> +    iov->iov_base += sizeof(can_frame_t);
>> +    iov->iov_len -= sizeof(can_frame_t);
>> +
>> +    ret = __rtcan_raw_sendmsg(dev, sock, frame, timeout);
>> +    if (ret < 0)
>> +        goto finally;
>> +
>> +    sent += ret;
>> +    }
>> +
>> +    /* copy it back to userspace if necessary */
>> +    if (rtdm_fd_is_user(fd)) {
>> +    if (rtdm_copy_to_user(fd, msg->msg_iov, iov, sizeof(struct iovec))) {
>> +        ret = -EFAULT;
>> +        goto finally;
>> +    }
>> +    }
>> +
>> +finally:
>> +    rtcan_dev_dereference(dev);
>> +
>> +    if (sent > 0)
>> +        return sent;
>> +
>> +    return ret;
>> +}
>>  
>>  static struct rtdm_driver rtcan_driver = {
>>      .profile_info           = RTDM_PROFILE_INFO(rtcan,
>>
> 

-- 
Siemens AG, T RDA IOT
Corporate Competence Center Embedded Linux

Reply via email to