On Tue, Oct 12, 2010 at 09:05:28AM +0200, Oliver Hartkopp wrote:
> On 12.10.2010 08:51, Kurt Van Dijck wrote:
> > On Mon, Oct 11, 2010 at 05:14:20PM +0200, [email protected] wrote:
> 
> So far i did not have any luck to push the MSG_DONTROUTE bit into userspace.
Happy to note I did.

I combined 2 things:
* notify 'local' originated messages (strictly speaking, this should not
  be necessary
* notify 'transmission confirmation' on sockets

below are 2 patches and a brand new C file:
1 patch (little modified from Oliver's patch. I thought  'L' from local
is more intuitive for regular users

1 patch for raw.c (kernel space). 2 flags are added.

1 test program. The problem I faced is that candump will never receive
a transmission confirmation (or self-reception) message, since it doesn't
send any traffic. This program does send initially a frame, which it will
read back shortly after.

Most of the code is a cowardly copy of candump.c, which I did not want to
touch for a proof-of-concept.

The patches are taken from different root's

Regards,
Kurt

proof-of-concept C file

#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <inttypes.h>
#include <error.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <net/if.h>

int main(int argc, char *argv[]) {
        int sk, ret, j;
        const char *dev = "can0";
        struct sockaddr_can addr;
        const int val = 1;
        struct ifreq ifr;
        struct can_frame frame;
        struct iovec iov;
        struct msghdr msg;
        struct cmsghdr *cmsg;
        struct timeval tv;
        static uint8_t ctrlmsg[CMSG_SPACE(sizeof(struct timeval)) + 
CMSG_SPACE(sizeof(__u32))];

        memset(&addr, 0, sizeof(addr));
        if (argc > 1)
                dev = argv[1];

        ret = sk = socket(PF_CAN, SOCK_RAW, CAN_RAW);
        if (ret < 0)
                error(1, errno, "socket");
        ret = setsockopt(sk, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS,
                        &val, sizeof(val));
        if (ret < 0)
                error(1, errno, "recv own");

        strcpy(ifr.ifr_name, dev);
        ret = ioctl(sk, SIOCGIFINDEX, &ifr);
        if (ret < 0)
                error(1, errno, "SOICGIFINDEX %s", dev);
        addr.can_family = AF_CAN;
        addr.can_ifindex = ifr.ifr_ifindex;

        ret = bind(sk, (void *)&addr, sizeof(addr));
        if (ret < 0)
                error(1, errno, "bind");

        // fixed settings
        iov.iov_base = &frame;
        msg.msg_name = &addr;
        msg.msg_iov = &iov;
        msg.msg_iovlen = 1;
        msg.msg_control = &ctrlmsg;

        memset(&frame, 0, sizeof(frame));
        frame.can_id = 0x123;
        frame.can_dlc = 2;
        frame.data[0] = 4;
        frame.data[1] = 5;
        ret = write(sk, &frame, sizeof(frame));
        if (ret < 0)
                error(1, errno, "can send");

        while (1) {
                /* these settings may be modified by recvmsg() */
                iov.iov_len = sizeof(frame);
                msg.msg_namelen = sizeof(addr);
                msg.msg_controllen = sizeof(ctrlmsg);  
                msg.msg_flags = 0;

                ret = recvmsg(sk, &msg, 0);
                if (ret < 0)
                        error(1, errno, "recvmsg");

                for (cmsg = CMSG_FIRSTHDR(&msg);
                                cmsg && (cmsg->cmsg_level == SOL_SOCKET);
                                cmsg = CMSG_NXTHDR(&msg,cmsg)) {
                        if (cmsg->cmsg_type == SO_TIMESTAMP)
                                tv = *(struct timeval *)CMSG_DATA(cmsg);
                }

                printf("(%ld.%06ld) ", tv.tv_sec, tv.tv_usec);
                printf(" %s", dev);
                if (msg.msg_flags & MSG_CONFIRM)
                        /* transmission confirmation */
                        printf(" T");
                else if (msg.msg_flags & MSG_DONTROUTE)
                        printf(" L");
                else
                        printf(" -");

                if (frame.can_id & CAN_EFF_FLAG)
                        printf(" %08lx:", frame.can_id);
                else
                        printf("      %03x:", frame.can_id);
                if (frame.can_id & CAN_RTR_FLAG)
                        printf(" rtr %u", frame.can_dlc);
                else for (j = 0; j < frame.can_dlc; ++j)
                        printf(" %02x", frame.data[j]);
                printf("\n");
                fflush(stdout);
        }
        return 0;
}
---
Index: can-utils/candump.c
===================================================================
--- can-utils/candump.c (revision 1198)
+++ can-utils/candump.c (working copy)
@@ -722,6 +722,11 @@
                                printf("%*s", max_devname_len, devname[idx]);
                                printf("%s  ", (color==1)?col_off:"");
 
+                               if (msg.msg_flags & MSG_DONTROUTE)
+                                       printf(" L");
+                               else
+                                       printf(" -");
+
                                fprint_long_canframe(stdout, &frame, NULL, 
view);
 
                                printf("%s", (color>1)?col_off:"");

---

Index: net/can/raw.c
===================================================================
--- net/can/raw.c       (revision 1198)
+++ net/can/raw.c       (working copy)
@@ -102,6 +102,15 @@
        can_err_mask_t err_mask;
 };
 
+#define RAWF_LOCAL     0x01
+#define RAWF_SELF      0x02
+static inline int *raw_flags(struct sk_buff *skb)
+{
+       BUILD_BUG_ON((sizeof(skb->cb)+sizeof(int)) <= sizeof(struct 
sockaddr_can));
+       /* return pointer after struct sockaddr_can */
+       return (int *)(&((struct sockaddr_can *)skb->cb)[1]);
+}
+
 static inline struct raw_sock *raw_sk(const struct sock *sk)
 {
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12)
@@ -111,18 +120,20 @@
 #endif
 }
 
-static void raw_rcv(struct sk_buff *skb, void *data)
+static void raw_rcv(struct sk_buff *oskb, void *data)
 {
        struct sock *sk = (struct sock *)data;
        struct raw_sock *ro = raw_sk(sk);
        struct sockaddr_can *addr;
+       struct sk_buff *skb;
+       int *pflags;
 
        /* check the received tx sock reference */
-       if (!ro->recv_own_msgs && skb->sk == sk)
+       if (!ro->recv_own_msgs && oskb->sk == sk)
                return;
 
        /* clone the given skb to be able to enqueue it into the rcv queue */
-       skb = skb_clone(skb, GFP_ATOMIC);
+       skb = skb_clone(oskb, GFP_ATOMIC);
        if (!skb)
                return;
 
@@ -139,6 +150,13 @@
        addr->can_family  = AF_CAN;
        addr->can_ifindex = skb->dev->ifindex;
 
+       pflags = raw_flags(skb);
+       *pflags = 0;
+       if (oskb->sk)
+               *pflags |= RAWF_LOCAL;
+       if (oskb->sk == sk)
+               *pflags |= RAWF_SELF;
+
        if (sock_queue_rcv_skb(sk, skb) < 0)
                kfree_skb(skb);
 }
@@ -713,6 +731,7 @@
        struct sk_buff *skb;
        int err = 0;
        int noblock;
+       int *pflags;
 
        noblock =  flags & MSG_DONTWAIT;
        flags   &= ~MSG_DONTWAIT;
@@ -739,6 +758,12 @@
                memcpy(msg->msg_name, skb->cb, msg->msg_namelen);
        }
 
+       pflags = raw_flags(skb);
+       if (*pflags & RAWF_LOCAL)
+               msg->msg_flags |= MSG_DONTROUTE;
+       if (*pflags & RAWF_SELF)
+               msg->msg_flags |= MSG_CONFIRM;
+
        skb_free_datagram(sk, skb);
 
        return size;
_______________________________________________
Socketcan-core mailing list
[email protected]
https://lists.berlios.de/mailman/listinfo/socketcan-core

Reply via email to