Commit ba61a8d9 authored by Arnd Bergmann's avatar Arnd Bergmann Committed by Marc Kleine-Budde

can: avoid using timeval for uapi

The can subsystem communicates with user space using a bcm_msg_head
header, which contains two timestamps. This is problematic for
multiple reasons:

a) The structure layout is currently incompatible between 64-bit
   user space and 32-bit user space, and cannot work in compat
   mode (other than x32).

b) The timeval structure layout will change in 32-bit user
   space when we fix the y2038 overflow problem by redefining
   time_t to 64-bit, making new 32-bit user space incompatible
   with the current kernel interface.
   Cars last a long time and often use old kernels, so the actual
   users of this code are the most likely ones to migrate to y2038
   safe user space.

This tries to work around part of the problem by changing the
publicly visible user interface in the header, but not the binary
interface. Fortunately, the values passed around in the structure
are relative times and do not actually suffer from the y2038
overflow, so 32-bit is enough here.

We replace the use of 'struct timeval' with a newly defined
'struct bcm_timeval' that uses the exact same binary layout
as before and that still suffers from problem a) but not problem
b).

The downside of this approach is that any user space program
that currently assigns a timeval structure to these members
rather than writing the tv_sec/tv_usec portions individually
will suffer a compile-time error when built with an updated
kernel header. Fixing this error makes it work fine with old
and new headers though.

We could address problem a) by using '__u32' or 'int' members
rather than 'long', but that would have a more significant
downside in also breaking support for all existing 64-bit user
binaries that might be using this interface, which is likely
not acceptable.
Signed-off-by: default avatarArnd Bergmann <arnd@arndb.de>
Acked-by: default avatarOliver Hartkopp <socketcan@hartkopp.net>
Cc: linux-can@vger.kernel.org
Cc: linux-api@vger.kernel.org
Signed-off-by: default avatarMarc Kleine-Budde <mkl@pengutronix.de>
parent 3c200db5
...@@ -47,6 +47,11 @@ ...@@ -47,6 +47,11 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/can.h> #include <linux/can.h>
struct bcm_timeval {
long tv_sec;
long tv_usec;
};
/** /**
* struct bcm_msg_head - head of messages to/from the broadcast manager * struct bcm_msg_head - head of messages to/from the broadcast manager
* @opcode: opcode, see enum below. * @opcode: opcode, see enum below.
...@@ -62,7 +67,7 @@ struct bcm_msg_head { ...@@ -62,7 +67,7 @@ struct bcm_msg_head {
__u32 opcode; __u32 opcode;
__u32 flags; __u32 flags;
__u32 count; __u32 count;
struct timeval ival1, ival2; struct bcm_timeval ival1, ival2;
canid_t can_id; canid_t can_id;
__u32 nframes; __u32 nframes;
struct can_frame frames[0]; struct can_frame frames[0];
......
...@@ -96,7 +96,7 @@ struct bcm_op { ...@@ -96,7 +96,7 @@ struct bcm_op {
canid_t can_id; canid_t can_id;
u32 flags; u32 flags;
unsigned long frames_abs, frames_filtered; unsigned long frames_abs, frames_filtered;
struct timeval ival1, ival2; struct bcm_timeval ival1, ival2;
struct hrtimer timer, thrtimer; struct hrtimer timer, thrtimer;
struct tasklet_struct tsklet, thrtsklet; struct tasklet_struct tsklet, thrtsklet;
ktime_t rx_stamp, kt_ival1, kt_ival2, kt_lastmsg; ktime_t rx_stamp, kt_ival1, kt_ival2, kt_lastmsg;
...@@ -131,6 +131,11 @@ static inline struct bcm_sock *bcm_sk(const struct sock *sk) ...@@ -131,6 +131,11 @@ static inline struct bcm_sock *bcm_sk(const struct sock *sk)
return (struct bcm_sock *)sk; return (struct bcm_sock *)sk;
} }
static inline ktime_t bcm_timeval_to_ktime(struct bcm_timeval tv)
{
return ktime_set(tv.tv_sec, tv.tv_usec * NSEC_PER_USEC);
}
#define CFSIZ sizeof(struct can_frame) #define CFSIZ sizeof(struct can_frame)
#define OPSIZ sizeof(struct bcm_op) #define OPSIZ sizeof(struct bcm_op)
#define MHSIZ sizeof(struct bcm_msg_head) #define MHSIZ sizeof(struct bcm_msg_head)
...@@ -953,8 +958,8 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg, ...@@ -953,8 +958,8 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
op->count = msg_head->count; op->count = msg_head->count;
op->ival1 = msg_head->ival1; op->ival1 = msg_head->ival1;
op->ival2 = msg_head->ival2; op->ival2 = msg_head->ival2;
op->kt_ival1 = timeval_to_ktime(msg_head->ival1); op->kt_ival1 = bcm_timeval_to_ktime(msg_head->ival1);
op->kt_ival2 = timeval_to_ktime(msg_head->ival2); op->kt_ival2 = bcm_timeval_to_ktime(msg_head->ival2);
/* disable an active timer due to zero values? */ /* disable an active timer due to zero values? */
if (!op->kt_ival1.tv64 && !op->kt_ival2.tv64) if (!op->kt_ival1.tv64 && !op->kt_ival2.tv64)
...@@ -1134,8 +1139,8 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg, ...@@ -1134,8 +1139,8 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
/* set timer value */ /* set timer value */
op->ival1 = msg_head->ival1; op->ival1 = msg_head->ival1;
op->ival2 = msg_head->ival2; op->ival2 = msg_head->ival2;
op->kt_ival1 = timeval_to_ktime(msg_head->ival1); op->kt_ival1 = bcm_timeval_to_ktime(msg_head->ival1);
op->kt_ival2 = timeval_to_ktime(msg_head->ival2); op->kt_ival2 = bcm_timeval_to_ktime(msg_head->ival2);
/* disable an active timer due to zero value? */ /* disable an active timer due to zero value? */
if (!op->kt_ival1.tv64) if (!op->kt_ival1.tv64)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment