linux-can-next-for-4.1-20150401
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABCAAGBQJVG8DxAAoJECte4hHFiupUkFkP+QEDROmDdcYQPRqNgVXvbNxo +uFBI+Y9ttnm+WCR9tu2v2NDuFsbPaD5ckK/idDypSS9tcQWcZqS8odPq9lFYTqu OvfH3lMT82myZf7MT6evn3l6Zwm3UM0fXRxvflpUyFsM8h8quOkhx+ckHK9rjhU7 vEDRDbg1r2xAvQcAm0ACwTCKIxqtf+xnRKwarR+q/1hiHUOmd455cR6uUc+ydAbt 94J4ltnUmpZOgBiNmhZBrD29cheKmwqVEsiv5RcFaRbilJmWM8HFOjsocMAbaz8O hoV8TQbQY1m2fc+sqBlJUr2YYBGnU1jHzhVP9fgAAvhjZGmRXT5zcEorN4m8sGn2 6/slVnkeUyy3wgrmqphk81qd86nTd51gMaI5ixs19eG4epjcQ04ORAZs4zkxVQDo wUNDS1CLdoGztJUjf4+fEjfU9FXXIrBbyXbpXGiNwogXpFCzSj+NNtEyuzaRlSok 72mn7ATxSKsrK0t0WJLv/m0mJfOPikQ1YN60g4SxLLlpK+dFarzojQLVyLrJGWxR cnseiB0IV2PvuV1RRrBntbXWK+rO4Y2PCMt46Hx63NrxwOzffa0s6MjXg3xLMc3p kl0RmoA/lDsIem0iBKF5PysOe7UsjklUO1jgqE53359FQDJDtg5N/BtnpB4wFQh5 NlfJ6q+TG58jYhiiONFN =+qN4 -----END PGP SIGNATURE----- Merge tag 'linux-can-next-for-4.1-20150401' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next Marc Kleine-Budde says: ==================== pull-request: can-next 2015-04-01 this is a pull request of 5 patches for net-next/master. There are two patches for the ems_usb driver by Gerhard Uttenthaler and me, which fix sparse endianess warnings. Oliver Hartkopp adds two patches to improve and extend the CAN-ID filter handling on RAW CAN sockets. The last patch is by me, it silences an uninitialized variable warning in the peak_usb driver. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
b9600d2d09
5 changed files with 74 additions and 10 deletions
|
@ -22,7 +22,8 @@ This file contains
|
||||||
4.1.3 RAW socket option CAN_RAW_LOOPBACK
|
4.1.3 RAW socket option CAN_RAW_LOOPBACK
|
||||||
4.1.4 RAW socket option CAN_RAW_RECV_OWN_MSGS
|
4.1.4 RAW socket option CAN_RAW_RECV_OWN_MSGS
|
||||||
4.1.5 RAW socket option CAN_RAW_FD_FRAMES
|
4.1.5 RAW socket option CAN_RAW_FD_FRAMES
|
||||||
4.1.6 RAW socket returned message flags
|
4.1.6 RAW socket option CAN_RAW_JOIN_FILTERS
|
||||||
|
4.1.7 RAW socket returned message flags
|
||||||
4.2 Broadcast Manager protocol sockets (SOCK_DGRAM)
|
4.2 Broadcast Manager protocol sockets (SOCK_DGRAM)
|
||||||
4.2.1 Broadcast Manager operations
|
4.2.1 Broadcast Manager operations
|
||||||
4.2.2 Broadcast Manager message flags
|
4.2.2 Broadcast Manager message flags
|
||||||
|
@ -601,7 +602,22 @@ solution for a couple of reasons:
|
||||||
CAN FD frames by checking if the device maximum transfer unit is CANFD_MTU.
|
CAN FD frames by checking if the device maximum transfer unit is CANFD_MTU.
|
||||||
The CAN device MTU can be retrieved e.g. with a SIOCGIFMTU ioctl() syscall.
|
The CAN device MTU can be retrieved e.g. with a SIOCGIFMTU ioctl() syscall.
|
||||||
|
|
||||||
4.1.6 RAW socket returned message flags
|
4.1.6 RAW socket option CAN_RAW_JOIN_FILTERS
|
||||||
|
|
||||||
|
The CAN_RAW socket can set multiple CAN identifier specific filters that
|
||||||
|
lead to multiple filters in the af_can.c filter processing. These filters
|
||||||
|
are indenpendent from each other which leads to logical OR'ed filters when
|
||||||
|
applied (see 4.1.1).
|
||||||
|
|
||||||
|
This socket option joines the given CAN filters in the way that only CAN
|
||||||
|
frames are passed to user space that matched *all* given CAN filters. The
|
||||||
|
semantic for the applied filters is therefore changed to a logical AND.
|
||||||
|
|
||||||
|
This is useful especially when the filterset is a combination of filters
|
||||||
|
where the CAN_INV_FILTER flag is set in order to notch single CAN IDs or
|
||||||
|
CAN ID ranges from the incoming traffic.
|
||||||
|
|
||||||
|
4.1.7 RAW socket returned message flags
|
||||||
|
|
||||||
When using recvmsg() call, the msg->msg_flags may contain following flags:
|
When using recvmsg() call, the msg->msg_flags may contain following flags:
|
||||||
|
|
||||||
|
|
|
@ -123,7 +123,7 @@ MODULE_LICENSE("GPL v2");
|
||||||
* CPC_MSG_TYPE_EXT_CAN_FRAME or CPC_MSG_TYPE_EXT_RTR_FRAME.
|
* CPC_MSG_TYPE_EXT_CAN_FRAME or CPC_MSG_TYPE_EXT_RTR_FRAME.
|
||||||
*/
|
*/
|
||||||
struct cpc_can_msg {
|
struct cpc_can_msg {
|
||||||
u32 id;
|
__le32 id;
|
||||||
u8 length;
|
u8 length;
|
||||||
u8 msg[8];
|
u8 msg[8];
|
||||||
};
|
};
|
||||||
|
@ -200,8 +200,8 @@ struct __packed ems_cpc_msg {
|
||||||
u8 type; /* type of message */
|
u8 type; /* type of message */
|
||||||
u8 length; /* length of data within union 'msg' */
|
u8 length; /* length of data within union 'msg' */
|
||||||
u8 msgid; /* confirmation handle */
|
u8 msgid; /* confirmation handle */
|
||||||
u32 ts_sec; /* timestamp in seconds */
|
__le32 ts_sec; /* timestamp in seconds */
|
||||||
u32 ts_nsec; /* timestamp in nano seconds */
|
__le32 ts_nsec; /* timestamp in nano seconds */
|
||||||
|
|
||||||
union {
|
union {
|
||||||
u8 generic[64];
|
u8 generic[64];
|
||||||
|
@ -765,7 +765,7 @@ static netdev_tx_t ems_usb_start_xmit(struct sk_buff *skb, struct net_device *ne
|
||||||
|
|
||||||
msg = (struct ems_cpc_msg *)&buf[CPC_HEADER_SIZE];
|
msg = (struct ems_cpc_msg *)&buf[CPC_HEADER_SIZE];
|
||||||
|
|
||||||
msg->msg.can_msg.id = cf->can_id & CAN_ERR_MASK;
|
msg->msg.can_msg.id = cpu_to_le32(cf->can_id & CAN_ERR_MASK);
|
||||||
msg->msg.can_msg.length = cf->can_dlc;
|
msg->msg.can_msg.length = cf->can_dlc;
|
||||||
|
|
||||||
if (cf->can_id & CAN_RTR_FLAG) {
|
if (cf->can_id & CAN_RTR_FLAG) {
|
||||||
|
@ -783,9 +783,6 @@ static netdev_tx_t ems_usb_start_xmit(struct sk_buff *skb, struct net_device *ne
|
||||||
msg->length = CPC_CAN_MSG_MIN_SIZE + cf->can_dlc;
|
msg->length = CPC_CAN_MSG_MIN_SIZE + cf->can_dlc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Respect byte order */
|
|
||||||
msg->msg.can_msg.id = cpu_to_le32(msg->msg.can_msg.id);
|
|
||||||
|
|
||||||
for (i = 0; i < MAX_TX_URBS; i++) {
|
for (i = 0; i < MAX_TX_URBS; i++) {
|
||||||
if (dev->tx_contexts[i].echo_index == MAX_TX_URBS) {
|
if (dev->tx_contexts[i].echo_index == MAX_TX_URBS) {
|
||||||
context = &dev->tx_contexts[i];
|
context = &dev->tx_contexts[i];
|
||||||
|
|
|
@ -182,7 +182,7 @@ static inline void *pcan_usb_fd_cmd_buffer(struct peak_usb_device *dev)
|
||||||
static int pcan_usb_fd_send_cmd(struct peak_usb_device *dev, void *cmd_tail)
|
static int pcan_usb_fd_send_cmd(struct peak_usb_device *dev, void *cmd_tail)
|
||||||
{
|
{
|
||||||
void *cmd_head = pcan_usb_fd_cmd_buffer(dev);
|
void *cmd_head = pcan_usb_fd_cmd_buffer(dev);
|
||||||
int err;
|
int err = 0;
|
||||||
u8 *packet_ptr;
|
u8 *packet_ptr;
|
||||||
int i, n = 1, packet_len;
|
int i, n = 1, packet_len;
|
||||||
ptrdiff_t cmd_len;
|
ptrdiff_t cmd_len;
|
||||||
|
|
|
@ -57,6 +57,7 @@ enum {
|
||||||
CAN_RAW_LOOPBACK, /* local loopback (default:on) */
|
CAN_RAW_LOOPBACK, /* local loopback (default:on) */
|
||||||
CAN_RAW_RECV_OWN_MSGS, /* receive my own msgs (default:off) */
|
CAN_RAW_RECV_OWN_MSGS, /* receive my own msgs (default:off) */
|
||||||
CAN_RAW_FD_FRAMES, /* allow CAN FD frames (default:off) */
|
CAN_RAW_FD_FRAMES, /* allow CAN FD frames (default:off) */
|
||||||
|
CAN_RAW_JOIN_FILTERS, /* all filters must match to trigger */
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* !_UAPI_CAN_RAW_H */
|
#endif /* !_UAPI_CAN_RAW_H */
|
||||||
|
|
|
@ -74,6 +74,12 @@ MODULE_ALIAS("can-proto-1");
|
||||||
* storing the single filter in dfilter, to avoid using dynamic memory.
|
* storing the single filter in dfilter, to avoid using dynamic memory.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
struct uniqframe {
|
||||||
|
ktime_t tstamp;
|
||||||
|
const struct sk_buff *skb;
|
||||||
|
unsigned int join_rx_count;
|
||||||
|
};
|
||||||
|
|
||||||
struct raw_sock {
|
struct raw_sock {
|
||||||
struct sock sk;
|
struct sock sk;
|
||||||
int bound;
|
int bound;
|
||||||
|
@ -82,10 +88,12 @@ struct raw_sock {
|
||||||
int loopback;
|
int loopback;
|
||||||
int recv_own_msgs;
|
int recv_own_msgs;
|
||||||
int fd_frames;
|
int fd_frames;
|
||||||
|
int join_filters;
|
||||||
int count; /* number of active filters */
|
int count; /* number of active filters */
|
||||||
struct can_filter dfilter; /* default/single filter */
|
struct can_filter dfilter; /* default/single filter */
|
||||||
struct can_filter *filter; /* pointer to filter(s) */
|
struct can_filter *filter; /* pointer to filter(s) */
|
||||||
can_err_mask_t err_mask;
|
can_err_mask_t err_mask;
|
||||||
|
struct uniqframe __percpu *uniq;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -123,6 +131,26 @@ static void raw_rcv(struct sk_buff *oskb, void *data)
|
||||||
if (!ro->fd_frames && oskb->len != CAN_MTU)
|
if (!ro->fd_frames && oskb->len != CAN_MTU)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/* eliminate multiple filter matches for the same skb */
|
||||||
|
if (this_cpu_ptr(ro->uniq)->skb == oskb &&
|
||||||
|
ktime_equal(this_cpu_ptr(ro->uniq)->tstamp, oskb->tstamp)) {
|
||||||
|
if (ro->join_filters) {
|
||||||
|
this_cpu_inc(ro->uniq->join_rx_count);
|
||||||
|
/* drop frame until all enabled filters matched */
|
||||||
|
if (this_cpu_ptr(ro->uniq)->join_rx_count < ro->count)
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this_cpu_ptr(ro->uniq)->skb = oskb;
|
||||||
|
this_cpu_ptr(ro->uniq)->tstamp = oskb->tstamp;
|
||||||
|
this_cpu_ptr(ro->uniq)->join_rx_count = 1;
|
||||||
|
/* drop first frame to check all enabled filters? */
|
||||||
|
if (ro->join_filters && ro->count > 1)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* clone the given skb to be able to enqueue it into the rcv queue */
|
/* clone the given skb to be able to enqueue it into the rcv queue */
|
||||||
skb = skb_clone(oskb, GFP_ATOMIC);
|
skb = skb_clone(oskb, GFP_ATOMIC);
|
||||||
if (!skb)
|
if (!skb)
|
||||||
|
@ -296,6 +324,12 @@ static int raw_init(struct sock *sk)
|
||||||
ro->loopback = 1;
|
ro->loopback = 1;
|
||||||
ro->recv_own_msgs = 0;
|
ro->recv_own_msgs = 0;
|
||||||
ro->fd_frames = 0;
|
ro->fd_frames = 0;
|
||||||
|
ro->join_filters = 0;
|
||||||
|
|
||||||
|
/* alloc_percpu provides zero'ed memory */
|
||||||
|
ro->uniq = alloc_percpu(struct uniqframe);
|
||||||
|
if (unlikely(!ro->uniq))
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
/* set notifier */
|
/* set notifier */
|
||||||
ro->notifier.notifier_call = raw_notifier;
|
ro->notifier.notifier_call = raw_notifier;
|
||||||
|
@ -339,6 +373,7 @@ static int raw_release(struct socket *sock)
|
||||||
ro->ifindex = 0;
|
ro->ifindex = 0;
|
||||||
ro->bound = 0;
|
ro->bound = 0;
|
||||||
ro->count = 0;
|
ro->count = 0;
|
||||||
|
free_percpu(ro->uniq);
|
||||||
|
|
||||||
sock_orphan(sk);
|
sock_orphan(sk);
|
||||||
sock->sk = NULL;
|
sock->sk = NULL;
|
||||||
|
@ -583,6 +618,15 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case CAN_RAW_JOIN_FILTERS:
|
||||||
|
if (optlen != sizeof(ro->join_filters))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (copy_from_user(&ro->join_filters, optval, optlen))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return -ENOPROTOOPT;
|
return -ENOPROTOOPT;
|
||||||
}
|
}
|
||||||
|
@ -647,6 +691,12 @@ static int raw_getsockopt(struct socket *sock, int level, int optname,
|
||||||
val = &ro->fd_frames;
|
val = &ro->fd_frames;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case CAN_RAW_JOIN_FILTERS:
|
||||||
|
if (len > sizeof(int))
|
||||||
|
len = sizeof(int);
|
||||||
|
val = &ro->join_filters;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return -ENOPROTOOPT;
|
return -ENOPROTOOPT;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue