|  | From 730cc5a78988344cff13340bbf0e1ab63f05d641 Mon Sep 17 00:00:00 2001 | 
|  | From: Oliver Hartkopp <socketcan@hartkopp.net> | 
|  | Date: Wed, 11 Aug 2010 16:12:35 -0700 | 
|  | Subject: can: add limit for nframes and clean up signed/unsigned variables | 
|  |  | 
|  |  | 
|  | From: Oliver Hartkopp <socketcan@hartkopp.net> | 
|  |  | 
|  | [ Upstream commit 5b75c4973ce779520b9d1e392483207d6f842cde ] | 
|  |  | 
|  | This patch adds a limit for nframes as the number of frames in TX_SETUP and | 
|  | RX_SETUP are derived from a single byte multiplex value by default. | 
|  | Use-cases that would require to send/filter more than 256 CAN frames should | 
|  | be implemented in userspace for complexity reasons anyway. | 
|  |  | 
|  | Additionally the assignments of unsigned values from userspace to signed | 
|  | values in kernelspace and vice versa are fixed by using unsigned values in | 
|  | kernelspace consistently. | 
|  |  | 
|  | Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net> | 
|  | Reported-by: Ben Hawkes <hawkes@google.com> | 
|  | Acked-by: Urs Thuermann <urs.thuermann@volkswagen.de> | 
|  | Signed-off-by: David S. Miller <davem@davemloft.net> | 
|  | Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> | 
|  | --- | 
|  | net/can/bcm.c |   41 +++++++++++++++++++++++++++-------------- | 
|  | 1 file changed, 27 insertions(+), 14 deletions(-) | 
|  |  | 
|  | --- a/net/can/bcm.c | 
|  | +++ b/net/can/bcm.c | 
|  | @@ -60,6 +60,13 @@ | 
|  | #include <net/sock.h> | 
|  | #include <net/net_namespace.h> | 
|  |  | 
|  | +/* | 
|  | + * To send multiple CAN frame content within TX_SETUP or to filter | 
|  | + * CAN messages with multiplex index within RX_SETUP, the number of | 
|  | + * different filters is limited to 256 due to the one byte index value. | 
|  | + */ | 
|  | +#define MAX_NFRAMES 256 | 
|  | + | 
|  | /* use of last_frames[index].can_dlc */ | 
|  | #define RX_RECV    0x40 /* received data for this element */ | 
|  | #define RX_THR     0x80 /* element not been sent due to throttle feature */ | 
|  | @@ -89,16 +96,16 @@ struct bcm_op { | 
|  | struct list_head list; | 
|  | int ifindex; | 
|  | canid_t can_id; | 
|  | -	int flags; | 
|  | +	u32 flags; | 
|  | unsigned long frames_abs, frames_filtered; | 
|  | struct timeval ival1, ival2; | 
|  | struct hrtimer timer, thrtimer; | 
|  | struct tasklet_struct tsklet, thrtsklet; | 
|  | ktime_t rx_stamp, kt_ival1, kt_ival2, kt_lastmsg; | 
|  | int rx_ifindex; | 
|  | -	int count; | 
|  | -	int nframes; | 
|  | -	int currframe; | 
|  | +	u32 count; | 
|  | +	u32 nframes; | 
|  | +	u32 currframe; | 
|  | struct can_frame *frames; | 
|  | struct can_frame *last_frames; | 
|  | struct can_frame sframe; | 
|  | @@ -175,7 +182,7 @@ static int bcm_proc_show(struct seq_file | 
|  |  | 
|  | seq_printf(m, "rx_op: %03X %-5s ", | 
|  | op->can_id, bcm_proc_getifname(ifname, op->ifindex)); | 
|  | -		seq_printf(m, "[%d]%c ", op->nframes, | 
|  | +		seq_printf(m, "[%u]%c ", op->nframes, | 
|  | (op->flags & RX_CHECK_DLC)?'d':' '); | 
|  | if (op->kt_ival1.tv64) | 
|  | seq_printf(m, "timeo=%lld ", | 
|  | @@ -198,7 +205,7 @@ static int bcm_proc_show(struct seq_file | 
|  |  | 
|  | list_for_each_entry(op, &bo->tx_ops, list) { | 
|  |  | 
|  | -		seq_printf(m, "tx_op: %03X %s [%d] ", | 
|  | +		seq_printf(m, "tx_op: %03X %s [%u] ", | 
|  | op->can_id, | 
|  | bcm_proc_getifname(ifname, op->ifindex), | 
|  | op->nframes); | 
|  | @@ -283,7 +290,7 @@ static void bcm_send_to_user(struct bcm_ | 
|  | struct can_frame *firstframe; | 
|  | struct sockaddr_can *addr; | 
|  | struct sock *sk = op->sk; | 
|  | -	int datalen = head->nframes * CFSIZ; | 
|  | +	unsigned int datalen = head->nframes * CFSIZ; | 
|  | int err; | 
|  |  | 
|  | skb = alloc_skb(sizeof(*head) + datalen, gfp_any()); | 
|  | @@ -468,7 +475,7 @@ rx_changed_settime: | 
|  | * bcm_rx_cmp_to_index - (bit)compares the currently received data to formerly | 
|  | *                       received data stored in op->last_frames[] | 
|  | */ | 
|  | -static void bcm_rx_cmp_to_index(struct bcm_op *op, int index, | 
|  | +static void bcm_rx_cmp_to_index(struct bcm_op *op, unsigned int index, | 
|  | const struct can_frame *rxdata) | 
|  | { | 
|  | /* | 
|  | @@ -554,7 +561,8 @@ static enum hrtimer_restart bcm_rx_timeo | 
|  | /* | 
|  | * bcm_rx_do_flush - helper for bcm_rx_thr_flush | 
|  | */ | 
|  | -static inline int bcm_rx_do_flush(struct bcm_op *op, int update, int index) | 
|  | +static inline int bcm_rx_do_flush(struct bcm_op *op, int update, | 
|  | +				  unsigned int index) | 
|  | { | 
|  | if ((op->last_frames) && (op->last_frames[index].can_dlc & RX_THR)) { | 
|  | if (update) | 
|  | @@ -575,7 +583,7 @@ static int bcm_rx_thr_flush(struct bcm_o | 
|  | int updated = 0; | 
|  |  | 
|  | if (op->nframes > 1) { | 
|  | -		int i; | 
|  | +		unsigned int i; | 
|  |  | 
|  | /* for MUX filter we start at index 1 */ | 
|  | for (i = 1; i < op->nframes; i++) | 
|  | @@ -624,7 +632,7 @@ static void bcm_rx_handler(struct sk_buf | 
|  | { | 
|  | struct bcm_op *op = (struct bcm_op *)data; | 
|  | const struct can_frame *rxframe = (struct can_frame *)skb->data; | 
|  | -	int i; | 
|  | +	unsigned int i; | 
|  |  | 
|  | /* disable timeout */ | 
|  | hrtimer_cancel(&op->timer); | 
|  | @@ -822,14 +830,15 @@ static int bcm_tx_setup(struct bcm_msg_h | 
|  | { | 
|  | struct bcm_sock *bo = bcm_sk(sk); | 
|  | struct bcm_op *op; | 
|  | -	int i, err; | 
|  | +	unsigned int i; | 
|  | +	int err; | 
|  |  | 
|  | /* we need a real device to send frames */ | 
|  | if (!ifindex) | 
|  | return -ENODEV; | 
|  |  | 
|  | -	/* we need at least one can_frame */ | 
|  | -	if (msg_head->nframes < 1) | 
|  | +	/* check nframes boundaries - we need at least one can_frame */ | 
|  | +	if (msg_head->nframes < 1 || msg_head->nframes > MAX_NFRAMES) | 
|  | return -EINVAL; | 
|  |  | 
|  | /* check the given can_id */ | 
|  | @@ -993,6 +1002,10 @@ static int bcm_rx_setup(struct bcm_msg_h | 
|  | msg_head->nframes = 0; | 
|  | } | 
|  |  | 
|  | +	/* the first element contains the mux-mask => MAX_NFRAMES + 1  */ | 
|  | +	if (msg_head->nframes > MAX_NFRAMES + 1) | 
|  | +		return -EINVAL; | 
|  | + | 
|  | if ((msg_head->flags & RX_RTR_FRAME) && | 
|  | ((msg_head->nframes != 1) || | 
|  | (!(msg_head->can_id & CAN_RTR_FLAG)))) |