diff options
| -rw-r--r-- | Documentation/networking/can.txt | 12 | ||||
| -rw-r--r-- | net/can/raw.c | 33 |
2 files changed, 42 insertions, 3 deletions
diff --git a/Documentation/networking/can.txt b/Documentation/networking/can.txt index cd79735013f9..5b04b67ddca2 100644 --- a/Documentation/networking/can.txt +++ b/Documentation/networking/can.txt | |||
| @@ -22,6 +22,7 @@ This file contains | |||
| 22 | 4.1.2 RAW socket option CAN_RAW_ERR_FILTER | 22 | 4.1.2 RAW socket option CAN_RAW_ERR_FILTER |
| 23 | 4.1.3 RAW socket option CAN_RAW_LOOPBACK | 23 | 4.1.3 RAW socket option CAN_RAW_LOOPBACK |
| 24 | 4.1.4 RAW socket option CAN_RAW_RECV_OWN_MSGS | 24 | 4.1.4 RAW socket option CAN_RAW_RECV_OWN_MSGS |
| 25 | 4.1.5 RAW socket returned message flags | ||
| 25 | 4.2 Broadcast Manager protocol sockets (SOCK_DGRAM) | 26 | 4.2 Broadcast Manager protocol sockets (SOCK_DGRAM) |
| 26 | 4.3 connected transport protocols (SOCK_SEQPACKET) | 27 | 4.3 connected transport protocols (SOCK_SEQPACKET) |
| 27 | 4.4 unconnected transport protocols (SOCK_DGRAM) | 28 | 4.4 unconnected transport protocols (SOCK_DGRAM) |
| @@ -471,6 +472,17 @@ solution for a couple of reasons: | |||
| 471 | setsockopt(s, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS, | 472 | setsockopt(s, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS, |
| 472 | &recv_own_msgs, sizeof(recv_own_msgs)); | 473 | &recv_own_msgs, sizeof(recv_own_msgs)); |
| 473 | 474 | ||
| 475 | 4.1.5 RAW socket returned message flags | ||
| 476 | |||
| 477 | When using recvmsg() call, the msg->msg_flags may contain following flags: | ||
| 478 | |||
| 479 | MSG_DONTROUTE: set when the received frame was created on the local host. | ||
| 480 | |||
| 481 | MSG_CONFIRM: set when the frame was sent via the socket it is received on. | ||
| 482 | This flag can be interpreted as a 'transmission confirmation' when the | ||
| 483 | CAN driver supports the echo of frames on driver level, see 3.2 and 6.2. | ||
| 484 | In order to receive such messages, CAN_RAW_RECV_OWN_MSGS must be set. | ||
| 485 | |||
| 474 | 4.2 Broadcast Manager protocol sockets (SOCK_DGRAM) | 486 | 4.2 Broadcast Manager protocol sockets (SOCK_DGRAM) |
| 475 | 4.3 connected transport protocols (SOCK_SEQPACKET) | 487 | 4.3 connected transport protocols (SOCK_SEQPACKET) |
| 476 | 4.4 unconnected transport protocols (SOCK_DGRAM) | 488 | 4.4 unconnected transport protocols (SOCK_DGRAM) |
diff --git a/net/can/raw.c b/net/can/raw.c index 7d77e67e57af..e88f610fdb7b 100644 --- a/net/can/raw.c +++ b/net/can/raw.c | |||
| @@ -90,23 +90,39 @@ struct raw_sock { | |||
| 90 | can_err_mask_t err_mask; | 90 | can_err_mask_t err_mask; |
| 91 | }; | 91 | }; |
| 92 | 92 | ||
| 93 | /* | ||
| 94 | * Return pointer to store the extra msg flags for raw_recvmsg(). | ||
| 95 | * We use the space of one unsigned int beyond the 'struct sockaddr_can' | ||
| 96 | * in skb->cb. | ||
| 97 | */ | ||
| 98 | static inline unsigned int *raw_flags(struct sk_buff *skb) | ||
| 99 | { | ||
| 100 | BUILD_BUG_ON(sizeof(skb->cb) <= (sizeof(struct sockaddr_can) + | ||
| 101 | sizeof(unsigned int))); | ||
| 102 | |||
| 103 | /* return pointer after struct sockaddr_can */ | ||
| 104 | return (unsigned int *)(&((struct sockaddr_can *)skb->cb)[1]); | ||
| 105 | } | ||
| 106 | |||
| 93 | static inline struct raw_sock *raw_sk(const struct sock *sk) | 107 | static inline struct raw_sock *raw_sk(const struct sock *sk) |
| 94 | { | 108 | { |
| 95 | return (struct raw_sock *)sk; | 109 | return (struct raw_sock *)sk; |
| 96 | } | 110 | } |
| 97 | 111 | ||
| 98 | static void raw_rcv(struct sk_buff *skb, void *data) | 112 | static void raw_rcv(struct sk_buff *oskb, void *data) |
| 99 | { | 113 | { |
| 100 | struct sock *sk = (struct sock *)data; | 114 | struct sock *sk = (struct sock *)data; |
| 101 | struct raw_sock *ro = raw_sk(sk); | 115 | struct raw_sock *ro = raw_sk(sk); |
| 102 | struct sockaddr_can *addr; | 116 | struct sockaddr_can *addr; |
| 117 | struct sk_buff *skb; | ||
| 118 | unsigned int *pflags; | ||
| 103 | 119 | ||
| 104 | /* check the received tx sock reference */ | 120 | /* check the received tx sock reference */ |
| 105 | if (!ro->recv_own_msgs && skb->sk == sk) | 121 | if (!ro->recv_own_msgs && oskb->sk == sk) |
| 106 | return; | 122 | return; |
| 107 | 123 | ||
| 108 | /* clone the given skb to be able to enqueue it into the rcv queue */ | 124 | /* clone the given skb to be able to enqueue it into the rcv queue */ |
| 109 | skb = skb_clone(skb, GFP_ATOMIC); | 125 | skb = skb_clone(oskb, GFP_ATOMIC); |
| 110 | if (!skb) | 126 | if (!skb) |
| 111 | return; | 127 | return; |
| 112 | 128 | ||
| @@ -123,6 +139,14 @@ static void raw_rcv(struct sk_buff *skb, void *data) | |||
| 123 | addr->can_family = AF_CAN; | 139 | addr->can_family = AF_CAN; |
| 124 | addr->can_ifindex = skb->dev->ifindex; | 140 | addr->can_ifindex = skb->dev->ifindex; |
| 125 | 141 | ||
| 142 | /* add CAN specific message flags for raw_recvmsg() */ | ||
| 143 | pflags = raw_flags(skb); | ||
| 144 | *pflags = 0; | ||
| 145 | if (oskb->sk) | ||
| 146 | *pflags |= MSG_DONTROUTE; | ||
| 147 | if (oskb->sk == sk) | ||
| 148 | *pflags |= MSG_CONFIRM; | ||
| 149 | |||
| 126 | if (sock_queue_rcv_skb(sk, skb) < 0) | 150 | if (sock_queue_rcv_skb(sk, skb) < 0) |
| 127 | kfree_skb(skb); | 151 | kfree_skb(skb); |
| 128 | } | 152 | } |
| @@ -707,6 +731,9 @@ static int raw_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
| 707 | memcpy(msg->msg_name, skb->cb, msg->msg_namelen); | 731 | memcpy(msg->msg_name, skb->cb, msg->msg_namelen); |
| 708 | } | 732 | } |
| 709 | 733 | ||
| 734 | /* assign the flags that have been recorded in raw_rcv() */ | ||
| 735 | msg->msg_flags |= *(raw_flags(skb)); | ||
| 736 | |||
| 710 | skb_free_datagram(sk, skb); | 737 | skb_free_datagram(sk, skb); |
| 711 | 738 | ||
| 712 | return size; | 739 | return size; |
