diff options
Diffstat (limited to 'net/core')
-rw-r--r-- | net/core/datagram.c | 43 |
1 files changed, 27 insertions, 16 deletions
diff --git a/net/core/datagram.c b/net/core/datagram.c index fbd6c76436d0..2d733131d7ce 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c | |||
@@ -115,10 +115,10 @@ out_noerr: | |||
115 | } | 115 | } |
116 | 116 | ||
117 | /** | 117 | /** |
118 | * skb_recv_datagram - Receive a datagram skbuff | 118 | * __skb_recv_datagram - Receive a datagram skbuff |
119 | * @sk: socket | 119 | * @sk: socket |
120 | * @flags: MSG_ flags | 120 | * @flags: MSG_ flags |
121 | * @noblock: blocking operation? | 121 | * @peeked: returns non-zero if this packet has been seen before |
122 | * @err: error code returned | 122 | * @err: error code returned |
123 | * | 123 | * |
124 | * Get a datagram skbuff, understands the peeking, nonblocking wakeups | 124 | * Get a datagram skbuff, understands the peeking, nonblocking wakeups |
@@ -143,8 +143,8 @@ out_noerr: | |||
143 | * quite explicitly by POSIX 1003.1g, don't change them without having | 143 | * quite explicitly by POSIX 1003.1g, don't change them without having |
144 | * the standard around please. | 144 | * the standard around please. |
145 | */ | 145 | */ |
146 | struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, | 146 | struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned flags, |
147 | int noblock, int *err) | 147 | int *peeked, int *err) |
148 | { | 148 | { |
149 | struct sk_buff *skb; | 149 | struct sk_buff *skb; |
150 | long timeo; | 150 | long timeo; |
@@ -156,7 +156,7 @@ struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, | |||
156 | if (error) | 156 | if (error) |
157 | goto no_packet; | 157 | goto no_packet; |
158 | 158 | ||
159 | timeo = sock_rcvtimeo(sk, noblock); | 159 | timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); |
160 | 160 | ||
161 | do { | 161 | do { |
162 | /* Again only user level code calls this function, so nothing | 162 | /* Again only user level code calls this function, so nothing |
@@ -165,18 +165,19 @@ struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, | |||
165 | * Look at current nfs client by the way... | 165 | * Look at current nfs client by the way... |
166 | * However, this function was corrent in any case. 8) | 166 | * However, this function was corrent in any case. 8) |
167 | */ | 167 | */ |
168 | if (flags & MSG_PEEK) { | 168 | unsigned long cpu_flags; |
169 | unsigned long cpu_flags; | 169 | |
170 | 170 | spin_lock_irqsave(&sk->sk_receive_queue.lock, cpu_flags); | |
171 | spin_lock_irqsave(&sk->sk_receive_queue.lock, | 171 | skb = skb_peek(&sk->sk_receive_queue); |
172 | cpu_flags); | 172 | if (skb) { |
173 | skb = skb_peek(&sk->sk_receive_queue); | 173 | *peeked = skb->peeked; |
174 | if (skb) | 174 | if (flags & MSG_PEEK) { |
175 | skb->peeked = 1; | ||
175 | atomic_inc(&skb->users); | 176 | atomic_inc(&skb->users); |
176 | spin_unlock_irqrestore(&sk->sk_receive_queue.lock, | 177 | } else |
177 | cpu_flags); | 178 | __skb_unlink(skb, &sk->sk_receive_queue); |
178 | } else | 179 | } |
179 | skb = skb_dequeue(&sk->sk_receive_queue); | 180 | spin_unlock_irqrestore(&sk->sk_receive_queue.lock, cpu_flags); |
180 | 181 | ||
181 | if (skb) | 182 | if (skb) |
182 | return skb; | 183 | return skb; |
@@ -194,6 +195,16 @@ no_packet: | |||
194 | *err = error; | 195 | *err = error; |
195 | return NULL; | 196 | return NULL; |
196 | } | 197 | } |
198 | EXPORT_SYMBOL(__skb_recv_datagram); | ||
199 | |||
200 | struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, | ||
201 | int noblock, int *err) | ||
202 | { | ||
203 | int peeked; | ||
204 | |||
205 | return __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0), | ||
206 | &peeked, err); | ||
207 | } | ||
197 | 208 | ||
198 | void skb_free_datagram(struct sock *sk, struct sk_buff *skb) | 209 | void skb_free_datagram(struct sock *sk, struct sk_buff *skb) |
199 | { | 210 | { |