]> Pileus Git - ~andy/linux/blobdiff - net/can/raw.c
can-raw: add msg_flags to distinguish local traffic
[~andy/linux] / net / can / raw.c
index 7d77e67e57af681bcdb6a10e54173f592b8f8abf..e88f610fdb7bb11e69cc1f5a0bf10846d5c7165c 100644 (file)
@@ -90,23 +90,39 @@ struct raw_sock {
        can_err_mask_t err_mask;
 };
 
+/*
+ * Return pointer to store the extra msg flags for raw_recvmsg().
+ * We use the space of one unsigned int beyond the 'struct sockaddr_can'
+ * in skb->cb.
+ */
+static inline unsigned int *raw_flags(struct sk_buff *skb)
+{
+       BUILD_BUG_ON(sizeof(skb->cb) <= (sizeof(struct sockaddr_can) +
+                                        sizeof(unsigned int)));
+
+       /* return pointer after struct sockaddr_can */
+       return (unsigned int *)(&((struct sockaddr_can *)skb->cb)[1]);
+}
+
 static inline struct raw_sock *raw_sk(const struct sock *sk)
 {
        return (struct raw_sock *)sk;
 }
 
-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;
+       unsigned 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;
 
@@ -123,6 +139,14 @@ static void raw_rcv(struct sk_buff *skb, void *data)
        addr->can_family  = AF_CAN;
        addr->can_ifindex = skb->dev->ifindex;
 
+       /* add CAN specific message flags for raw_recvmsg() */
+       pflags = raw_flags(skb);
+       *pflags = 0;
+       if (oskb->sk)
+               *pflags |= MSG_DONTROUTE;
+       if (oskb->sk == sk)
+               *pflags |= MSG_CONFIRM;
+
        if (sock_queue_rcv_skb(sk, skb) < 0)
                kfree_skb(skb);
 }
@@ -707,6 +731,9 @@ static int raw_recvmsg(struct kiocb *iocb, struct socket *sock,
                memcpy(msg->msg_name, skb->cb, msg->msg_namelen);
        }
 
+       /* assign the flags that have been recorded in raw_rcv() */
+       msg->msg_flags |= *(raw_flags(skb));
+
        skb_free_datagram(sk, skb);
 
        return size;