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