aboutsummaryrefslogtreecommitdiffstats
path: root/net/nfc/llcp/sock.c
diff options
context:
space:
mode:
authorSamuel Ortiz <sameo@linux.intel.com>2013-02-22 04:53:25 -0500
committerSamuel Ortiz <sameo@linux.intel.com>2013-03-10 17:20:05 -0400
commit26fd76cab2e61cedc5c25f7151fb31b57ddc53c7 (patch)
tree7958aad8711d1d7eaacb6aa2e4f9c0aae7a2da87 /net/nfc/llcp/sock.c
parente4306bec47fc02178c612879c848d3a6544424dd (diff)
NFC: llcp: Implement socket options
Some LLCP services (e.g. the validation ones) require some control over the LLCP link parameters like the receive window (RW) or the MIU extension (MIUX). This can only be done through socket options. Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'net/nfc/llcp/sock.c')
-rw-r--r--net/nfc/llcp/sock.c119
1 files changed, 117 insertions, 2 deletions
diff --git a/net/nfc/llcp/sock.c b/net/nfc/llcp/sock.c
index cc564992ba95..9357a756f7a9 100644
--- a/net/nfc/llcp/sock.c
+++ b/net/nfc/llcp/sock.c
@@ -223,6 +223,121 @@ error:
223 return ret; 223 return ret;
224} 224}
225 225
226static int nfc_llcp_setsockopt(struct socket *sock, int level, int optname,
227 char __user *optval, unsigned int optlen)
228{
229 struct sock *sk = sock->sk;
230 struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk);
231 u32 opt;
232 int err = 0;
233
234 pr_debug("%p optname %d\n", sk, optname);
235
236 if (level != SOL_NFC)
237 return -ENOPROTOOPT;
238
239 lock_sock(sk);
240
241 switch (optname) {
242 case NFC_LLCP_RW:
243 if (sk->sk_state == LLCP_CONNECTED ||
244 sk->sk_state == LLCP_BOUND ||
245 sk->sk_state == LLCP_LISTEN) {
246 err = -EINVAL;
247 break;
248 }
249
250 if (get_user(opt, (u32 __user *) optval)) {
251 err = -EFAULT;
252 break;
253 }
254
255 if (opt > LLCP_MAX_RW) {
256 err = -EINVAL;
257 break;
258 }
259
260 llcp_sock->rw = (u8) opt;
261
262 break;
263
264 case NFC_LLCP_MIUX:
265 if (sk->sk_state == LLCP_CONNECTED ||
266 sk->sk_state == LLCP_BOUND ||
267 sk->sk_state == LLCP_LISTEN) {
268 err = -EINVAL;
269 break;
270 }
271
272 if (get_user(opt, (u32 __user *) optval)) {
273 err = -EFAULT;
274 break;
275 }
276
277 if (opt > LLCP_MAX_MIUX) {
278 err = -EINVAL;
279 break;
280 }
281
282 llcp_sock->miux = (u16) opt;
283
284 break;
285
286 default:
287 err = -ENOPROTOOPT;
288 break;
289 }
290
291 release_sock(sk);
292
293 return err;
294}
295
296static int nfc_llcp_getsockopt(struct socket *sock, int level, int optname,
297 char __user *optval, int __user *optlen)
298{
299 struct sock *sk = sock->sk;
300 struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk);
301 int len, err = 0;
302
303 pr_debug("%p optname %d\n", sk, optname);
304
305 if (level != SOL_NFC)
306 return -ENOPROTOOPT;
307
308 if (get_user(len, optlen))
309 return -EFAULT;
310
311 len = min_t(u32, len, sizeof(u32));
312
313 lock_sock(sk);
314
315 switch (optname) {
316 case NFC_LLCP_RW:
317 if (put_user(llcp_sock->rw, (u32 __user *) optval))
318 err = -EFAULT;
319
320 break;
321
322 case NFC_LLCP_MIUX:
323 if (put_user(llcp_sock->miux, (u32 __user *) optval))
324 err = -EFAULT;
325
326 break;
327
328 default:
329 err = -ENOPROTOOPT;
330 break;
331 }
332
333 release_sock(sk);
334
335 if (put_user(len, optlen))
336 return -EFAULT;
337
338 return err;
339}
340
226void nfc_llcp_accept_unlink(struct sock *sk) 341void nfc_llcp_accept_unlink(struct sock *sk)
227{ 342{
228 struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk); 343 struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk);
@@ -735,8 +850,8 @@ static const struct proto_ops llcp_sock_ops = {
735 .ioctl = sock_no_ioctl, 850 .ioctl = sock_no_ioctl,
736 .listen = llcp_sock_listen, 851 .listen = llcp_sock_listen,
737 .shutdown = sock_no_shutdown, 852 .shutdown = sock_no_shutdown,
738 .setsockopt = sock_no_setsockopt, 853 .setsockopt = nfc_llcp_setsockopt,
739 .getsockopt = sock_no_getsockopt, 854 .getsockopt = nfc_llcp_getsockopt,
740 .sendmsg = llcp_sock_sendmsg, 855 .sendmsg = llcp_sock_sendmsg,
741 .recvmsg = llcp_sock_recvmsg, 856 .recvmsg = llcp_sock_recvmsg,
742 .mmap = sock_no_mmap, 857 .mmap = sock_no_mmap,