Merge tag 'linux-can-next-for-4.1-20150401' of git://git.kernel.org/pub/scm/linux...
authorDavid S. Miller <davem@davemloft.net>
Wed, 1 Apr 2015 17:58:06 +0000 (13:58 -0400)
committerDavid S. Miller <davem@davemloft.net>
Wed, 1 Apr 2015 17:58:06 +0000 (13:58 -0400)
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>
Documentation/networking/can.txt
drivers/net/can/usb/ems_usb.c
drivers/net/can/usb/peak_usb/pcan_usb_fd.c
include/uapi/linux/can/raw.h
net/can/raw.c

index 0a2859a8ee7ec66e6f2da253ca345b9d0f6d4ed1..5abad1e921ca810c1e765d1d84d1ca4a50ce5016 100644 (file)
@@ -22,7 +22,8 @@ This file contains
       4.1.3 RAW socket option CAN_RAW_LOOPBACK
       4.1.4 RAW socket option CAN_RAW_RECV_OWN_MSGS
       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.1 Broadcast Manager operations
       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.
   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:
 
index 9376f5e5b94ed2956c85808c5642ccbdb34036bd..866bac0ae7e966855d1085f5a8735988832a1bb7 100644 (file)
@@ -123,7 +123,7 @@ MODULE_LICENSE("GPL v2");
  * CPC_MSG_TYPE_EXT_CAN_FRAME or CPC_MSG_TYPE_EXT_RTR_FRAME.
  */
 struct cpc_can_msg {
-       u32 id;
+       __le32 id;
        u8 length;
        u8 msg[8];
 };
@@ -200,8 +200,8 @@ struct __packed ems_cpc_msg {
        u8 type;        /* type of message */
        u8 length;      /* length of data within union 'msg' */
        u8 msgid;       /* confirmation handle */
-       u32 ts_sec;     /* timestamp in seconds */
-       u32 ts_nsec;    /* timestamp in nano seconds */
+       __le32 ts_sec;  /* timestamp in seconds */
+       __le32 ts_nsec; /* timestamp in nano seconds */
 
        union {
                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->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;
 
        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;
        }
 
-       /* Respect byte order */
-       msg->msg.can_msg.id = cpu_to_le32(msg->msg.can_msg.id);
-
        for (i = 0; i < MAX_TX_URBS; i++) {
                if (dev->tx_contexts[i].echo_index == MAX_TX_URBS) {
                        context = &dev->tx_contexts[i];
index 0bac0f14edc3cd73727b4a0d9f0776d857c4ba8c..00481eeb9924ce96f0d5f734ff89a798c67d3eb1 100644 (file)
@@ -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)
 {
        void *cmd_head = pcan_usb_fd_cmd_buffer(dev);
-       int err;
+       int err = 0;
        u8 *packet_ptr;
        int i, n = 1, packet_len;
        ptrdiff_t cmd_len;
index 78ec76fd89a6ce4fe70161576ec0c01e5d6156d3..8735f1080385d045fff82660fd53c3a79dd98fc8 100644 (file)
@@ -57,6 +57,7 @@ enum {
        CAN_RAW_LOOPBACK,       /* local loopback (default:on)       */
        CAN_RAW_RECV_OWN_MSGS,  /* receive my own msgs (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 */
index 63ffdb0f3a23fa6bea6b9cb65bd7a63ec0953d84..31b9748cbb4ec6c1caa9ddc9e3a80609077a81eb 100644 (file)
@@ -74,6 +74,12 @@ MODULE_ALIAS("can-proto-1");
  * 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 sock sk;
        int bound;
@@ -82,10 +88,12 @@ struct raw_sock {
        int loopback;
        int recv_own_msgs;
        int fd_frames;
+       int join_filters;
        int count;                 /* number of active filters */
        struct can_filter dfilter; /* default/single filter */
        struct can_filter *filter; /* pointer to filter(s) */
        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)
                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 */
        skb = skb_clone(oskb, GFP_ATOMIC);
        if (!skb)
@@ -296,6 +324,12 @@ static int raw_init(struct sock *sk)
        ro->loopback         = 1;
        ro->recv_own_msgs    = 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 */
        ro->notifier.notifier_call = raw_notifier;
@@ -339,6 +373,7 @@ static int raw_release(struct socket *sock)
        ro->ifindex = 0;
        ro->bound   = 0;
        ro->count   = 0;
+       free_percpu(ro->uniq);
 
        sock_orphan(sk);
        sock->sk = NULL;
@@ -583,6 +618,15 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
 
                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:
                return -ENOPROTOOPT;
        }
@@ -647,6 +691,12 @@ static int raw_getsockopt(struct socket *sock, int level, int optname,
                val = &ro->fd_frames;
                break;
 
+       case CAN_RAW_JOIN_FILTERS:
+               if (len > sizeof(int))
+                       len = sizeof(int);
+               val = &ro->join_filters;
+               break;
+
        default:
                return -ENOPROTOOPT;
        }
This page took 0.030152 seconds and 5 git commands to generate.