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; |