Blame view

net/nfc/llcp_sock.c 22.4 KB
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  /*
   * Copyright (C) 2011  Intel Corporation. All rights reserved.
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
98b32decc   Jeff Kirsher   nfc: Fix FSF addr...
15
   * along with this program; if not, see <http://www.gnu.org/licenses/>.
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
16
17
18
19
20
21
22
23
   */
  
  #define pr_fmt(fmt) "llcp: %s: " fmt, __func__
  
  #include <linux/init.h>
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/nfc.h>
174cd4b1e   Ingo Molnar   sched/headers: Pr...
24
  #include <linux/sched/signal.h>
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
25

30cc45876   Samuel Ortiz   NFC: Move LLCP co...
26
  #include "nfc.h"
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
27
  #include "llcp.h"
ff353d86a   Samuel Ortiz   NFC: LLCP connect...
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
  static int sock_wait_state(struct sock *sk, int state, unsigned long timeo)
  {
  	DECLARE_WAITQUEUE(wait, current);
  	int err = 0;
  
  	pr_debug("sk %p", sk);
  
  	add_wait_queue(sk_sleep(sk), &wait);
  	set_current_state(TASK_INTERRUPTIBLE);
  
  	while (sk->sk_state != state) {
  		if (!timeo) {
  			err = -EINPROGRESS;
  			break;
  		}
  
  		if (signal_pending(current)) {
  			err = sock_intr_errno(timeo);
  			break;
  		}
  
  		release_sock(sk);
  		timeo = schedule_timeout(timeo);
  		lock_sock(sk);
  		set_current_state(TASK_INTERRUPTIBLE);
  
  		err = sock_error(sk);
  		if (err)
  			break;
  	}
  
  	__set_current_state(TASK_RUNNING);
  	remove_wait_queue(sk_sleep(sk), &wait);
  	return err;
  }
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
63
64
65
66
67
68
69
70
71
72
73
74
75
76
  static struct proto llcp_sock_proto = {
  	.name     = "NFC_LLCP",
  	.owner    = THIS_MODULE,
  	.obj_size = sizeof(struct nfc_llcp_sock),
  };
  
  static int llcp_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
  {
  	struct sock *sk = sock->sk;
  	struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk);
  	struct nfc_llcp_local *local;
  	struct nfc_dev *dev;
  	struct sockaddr_nfc_llcp llcp_addr;
  	int len, ret = 0;
f6a5885fc   Mateusz Jurczyk   NFC: Add sockaddr...
77
78
  	if (!addr || alen < offsetofend(struct sockaddr, sa_family) ||
  	    addr->sa_family != AF_NFC)
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
79
  		return -EINVAL;
c66433dc5   Samuel Ortiz   NFC: Dereference ...
80
81
  	pr_debug("sk %p addr %p family %d
  ", sk, addr, addr->sa_family);
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
  	memset(&llcp_addr, 0, sizeof(llcp_addr));
  	len = min_t(unsigned int, sizeof(llcp_addr), alen);
  	memcpy(&llcp_addr, addr, len);
  
  	/* This is going to be a listening socket, dsap must be 0 */
  	if (llcp_addr.dsap != 0)
  		return -EINVAL;
  
  	lock_sock(sk);
  
  	if (sk->sk_state != LLCP_CLOSED) {
  		ret = -EBADFD;
  		goto error;
  	}
  
  	dev = nfc_get_device(llcp_addr.dev_idx);
  	if (dev == NULL) {
  		ret = -ENODEV;
  		goto error;
  	}
  
  	local = nfc_llcp_find_local(dev);
  	if (local == NULL) {
  		ret = -ENODEV;
  		goto put_dev;
  	}
  
  	llcp_sock->dev = dev;
c7aa12252   Samuel Ortiz   NFC: Take a refer...
110
  	llcp_sock->local = nfc_llcp_local_get(local);
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
111
112
  	llcp_sock->nfc_protocol = llcp_addr.nfc_protocol;
  	llcp_sock->service_name_len = min_t(unsigned int,
427a2eb1f   Samuel Ortiz   NFC: LLCP code id...
113
114
  					    llcp_addr.service_name_len,
  					    NFC_LLCP_MAX_SERVICE_NAME);
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
115
  	llcp_sock->service_name = kmemdup(llcp_addr.service_name,
427a2eb1f   Samuel Ortiz   NFC: LLCP code id...
116
117
  					  llcp_sock->service_name_len,
  					  GFP_KERNEL);
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
118
119
  
  	llcp_sock->ssap = nfc_llcp_get_sdp_ssap(local, llcp_sock);
8b7e8eda5   Samuel Ortiz   NFC: Forbid LLCP ...
120
121
  	if (llcp_sock->ssap == LLCP_SAP_MAX) {
  		ret = -EADDRINUSE;
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
122
  		goto put_dev;
8b7e8eda5   Samuel Ortiz   NFC: Forbid LLCP ...
123
  	}
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
124

cbbf47218   Samuel Ortiz   NFC: Release LLCP...
125
  	llcp_sock->reserved_ssap = llcp_sock->ssap;
a69f32af8   Samuel Ortiz   NFC: Socket linke...
126
  	nfc_llcp_sock_link(&local->sockets, sk);
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
127
128
129
130
131
132
133
134
135
136
137
138
139
  
  	pr_debug("Socket bound to SAP %d
  ", llcp_sock->ssap);
  
  	sk->sk_state = LLCP_BOUND;
  
  put_dev:
  	nfc_put_device(dev);
  
  error:
  	release_sock(sk);
  	return ret;
  }
4463523be   Thierry Escande   NFC: LLCP raw soc...
140
141
142
143
144
145
146
147
148
  static int llcp_raw_sock_bind(struct socket *sock, struct sockaddr *addr,
  			      int alen)
  {
  	struct sock *sk = sock->sk;
  	struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk);
  	struct nfc_llcp_local *local;
  	struct nfc_dev *dev;
  	struct sockaddr_nfc_llcp llcp_addr;
  	int len, ret = 0;
f6a5885fc   Mateusz Jurczyk   NFC: Add sockaddr...
149
150
  	if (!addr || alen < offsetofend(struct sockaddr, sa_family) ||
  	    addr->sa_family != AF_NFC)
4463523be   Thierry Escande   NFC: LLCP raw soc...
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
  		return -EINVAL;
  
  	pr_debug("sk %p addr %p family %d
  ", sk, addr, addr->sa_family);
  
  	memset(&llcp_addr, 0, sizeof(llcp_addr));
  	len = min_t(unsigned int, sizeof(llcp_addr), alen);
  	memcpy(&llcp_addr, addr, len);
  
  	lock_sock(sk);
  
  	if (sk->sk_state != LLCP_CLOSED) {
  		ret = -EBADFD;
  		goto error;
  	}
  
  	dev = nfc_get_device(llcp_addr.dev_idx);
  	if (dev == NULL) {
  		ret = -ENODEV;
  		goto error;
  	}
  
  	local = nfc_llcp_find_local(dev);
  	if (local == NULL) {
  		ret = -ENODEV;
  		goto put_dev;
  	}
  
  	llcp_sock->dev = dev;
  	llcp_sock->local = nfc_llcp_local_get(local);
  	llcp_sock->nfc_protocol = llcp_addr.nfc_protocol;
  
  	nfc_llcp_sock_link(&local->raw_sockets, sk);
  
  	sk->sk_state = LLCP_BOUND;
  
  put_dev:
  	nfc_put_device(dev);
  
  error:
  	release_sock(sk);
  	return ret;
  }
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
194
195
196
197
198
199
200
201
202
  static int llcp_sock_listen(struct socket *sock, int backlog)
  {
  	struct sock *sk = sock->sk;
  	int ret = 0;
  
  	pr_debug("sk %p backlog %d
  ", sk, backlog);
  
  	lock_sock(sk);
874934f4d   Szymon Janc   NFC: Fix style is...
203
204
  	if ((sock->type != SOCK_SEQPACKET && sock->type != SOCK_STREAM) ||
  	    sk->sk_state != LLCP_BOUND) {
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
  		ret = -EBADFD;
  		goto error;
  	}
  
  	sk->sk_max_ack_backlog = backlog;
  	sk->sk_ack_backlog = 0;
  
  	pr_debug("Socket listening
  ");
  	sk->sk_state = LLCP_LISTEN;
  
  error:
  	release_sock(sk);
  
  	return ret;
  }
26fd76cab   Samuel Ortiz   NFC: llcp: Implem...
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
  static int nfc_llcp_setsockopt(struct socket *sock, int level, int optname,
  			       char __user *optval, unsigned int optlen)
  {
  	struct sock *sk = sock->sk;
  	struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk);
  	u32 opt;
  	int err = 0;
  
  	pr_debug("%p optname %d
  ", sk, optname);
  
  	if (level != SOL_NFC)
  		return -ENOPROTOOPT;
  
  	lock_sock(sk);
  
  	switch (optname) {
  	case NFC_LLCP_RW:
  		if (sk->sk_state == LLCP_CONNECTED ||
  		    sk->sk_state == LLCP_BOUND ||
  		    sk->sk_state == LLCP_LISTEN) {
  			err = -EINVAL;
  			break;
  		}
  
  		if (get_user(opt, (u32 __user *) optval)) {
  			err = -EFAULT;
  			break;
  		}
  
  		if (opt > LLCP_MAX_RW) {
  			err = -EINVAL;
  			break;
  		}
  
  		llcp_sock->rw = (u8) opt;
  
  		break;
  
  	case NFC_LLCP_MIUX:
  		if (sk->sk_state == LLCP_CONNECTED ||
  		    sk->sk_state == LLCP_BOUND ||
  		    sk->sk_state == LLCP_LISTEN) {
  			err = -EINVAL;
  			break;
  		}
  
  		if (get_user(opt, (u32 __user *) optval)) {
  			err = -EFAULT;
  			break;
  		}
  
  		if (opt > LLCP_MAX_MIUX) {
  			err = -EINVAL;
  			break;
  		}
5eef66697   Samuel Ortiz   NFC: llcp: Socket...
277
  		llcp_sock->miux = cpu_to_be16((u16) opt);
26fd76cab   Samuel Ortiz   NFC: llcp: Implem...
278
279
280
281
282
283
284
285
286
  
  		break;
  
  	default:
  		err = -ENOPROTOOPT;
  		break;
  	}
  
  	release_sock(sk);
06d44f806   Samuel Ortiz   NFC: llcp: Use so...
287
288
289
  	pr_debug("%p rw %d miux %d
  ", llcp_sock,
  		 llcp_sock->rw, llcp_sock->miux);
26fd76cab   Samuel Ortiz   NFC: llcp: Implem...
290
291
292
293
294
295
  	return err;
  }
  
  static int nfc_llcp_getsockopt(struct socket *sock, int level, int optname,
  			       char __user *optval, int __user *optlen)
  {
00e856db4   Samuel Ortiz   NFC: llcp: Fall b...
296
  	struct nfc_llcp_local *local;
26fd76cab   Samuel Ortiz   NFC: llcp: Implem...
297
298
299
  	struct sock *sk = sock->sk;
  	struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk);
  	int len, err = 0;
064f370c5   Thierry Escande   NFC: llcp: Add su...
300
  	u16 miux, remote_miu;
00e856db4   Samuel Ortiz   NFC: llcp: Fall b...
301
  	u8 rw;
26fd76cab   Samuel Ortiz   NFC: llcp: Implem...
302
303
304
305
306
307
308
309
310
  
  	pr_debug("%p optname %d
  ", sk, optname);
  
  	if (level != SOL_NFC)
  		return -ENOPROTOOPT;
  
  	if (get_user(len, optlen))
  		return -EFAULT;
00e856db4   Samuel Ortiz   NFC: llcp: Fall b...
311
312
313
  	local = llcp_sock->local;
  	if (!local)
  		return -ENODEV;
26fd76cab   Samuel Ortiz   NFC: llcp: Implem...
314
315
316
317
318
319
  	len = min_t(u32, len, sizeof(u32));
  
  	lock_sock(sk);
  
  	switch (optname) {
  	case NFC_LLCP_RW:
00e856db4   Samuel Ortiz   NFC: llcp: Fall b...
320
321
  		rw = llcp_sock->rw > LLCP_MAX_RW ? local->rw : llcp_sock->rw;
  		if (put_user(rw, (u32 __user *) optval))
26fd76cab   Samuel Ortiz   NFC: llcp: Implem...
322
323
324
325
326
  			err = -EFAULT;
  
  		break;
  
  	case NFC_LLCP_MIUX:
00e856db4   Samuel Ortiz   NFC: llcp: Fall b...
327
328
329
330
  		miux = be16_to_cpu(llcp_sock->miux) > LLCP_MAX_MIUX ?
  			be16_to_cpu(local->miux) : be16_to_cpu(llcp_sock->miux);
  
  		if (put_user(miux, (u32 __user *) optval))
26fd76cab   Samuel Ortiz   NFC: llcp: Implem...
331
332
333
  			err = -EFAULT;
  
  		break;
064f370c5   Thierry Escande   NFC: llcp: Add su...
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
  	case NFC_LLCP_REMOTE_MIU:
  		remote_miu = llcp_sock->remote_miu > LLCP_MAX_MIU ?
  				local->remote_miu : llcp_sock->remote_miu;
  
  		if (put_user(remote_miu, (u32 __user *) optval))
  			err = -EFAULT;
  
  		break;
  
  	case NFC_LLCP_REMOTE_LTO:
  		if (put_user(local->remote_lto / 10, (u32 __user *) optval))
  			err = -EFAULT;
  
  		break;
  
  	case NFC_LLCP_REMOTE_RW:
  		if (put_user(llcp_sock->remote_rw, (u32 __user *) optval))
26fd76cab   Samuel Ortiz   NFC: llcp: Implem...
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
  			err = -EFAULT;
  
  		break;
  
  	default:
  		err = -ENOPROTOOPT;
  		break;
  	}
  
  	release_sock(sk);
  
  	if (put_user(len, optlen))
  		return -EFAULT;
  
  	return err;
  }
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
  void nfc_llcp_accept_unlink(struct sock *sk)
  {
  	struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk);
  
  	pr_debug("state %d
  ", sk->sk_state);
  
  	list_del_init(&llcp_sock->accept_queue);
  	sk_acceptq_removed(llcp_sock->parent);
  	llcp_sock->parent = NULL;
  
  	sock_put(sk);
  }
  
  void nfc_llcp_accept_enqueue(struct sock *parent, struct sock *sk)
  {
  	struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk);
  	struct nfc_llcp_sock *llcp_sock_parent = nfc_llcp_sock(parent);
  
  	/* Lock will be free from unlink */
  	sock_hold(sk);
  
  	list_add_tail(&llcp_sock->accept_queue,
427a2eb1f   Samuel Ortiz   NFC: LLCP code id...
390
  		      &llcp_sock_parent->accept_queue);
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
391
392
393
394
395
  	llcp_sock->parent = parent;
  	sk_acceptq_added(parent);
  }
  
  struct sock *nfc_llcp_accept_dequeue(struct sock *parent,
427a2eb1f   Samuel Ortiz   NFC: LLCP code id...
396
  				     struct socket *newsock)
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
397
398
399
400
401
402
403
  {
  	struct nfc_llcp_sock *lsk, *n, *llcp_parent;
  	struct sock *sk;
  
  	llcp_parent = nfc_llcp_sock(parent);
  
  	list_for_each_entry_safe(lsk, n, &llcp_parent->accept_queue,
427a2eb1f   Samuel Ortiz   NFC: LLCP code id...
404
  				 accept_queue) {
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
405
406
407
408
409
410
411
412
413
414
  		sk = &lsk->sk;
  		lock_sock(sk);
  
  		if (sk->sk_state == LLCP_CLOSED) {
  			release_sock(sk);
  			nfc_llcp_accept_unlink(sk);
  			continue;
  		}
  
  		if (sk->sk_state == LLCP_CONNECTED || !newsock) {
39a352a5b   Samuel Ortiz   NFC: llcp: Keep t...
415
416
  			list_del_init(&lsk->accept_queue);
  			sock_put(sk);
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
417
418
419
420
421
422
423
  			if (newsock)
  				sock_graft(sk, newsock);
  
  			release_sock(sk);
  
  			pr_debug("Returning sk state %d
  ", sk->sk_state);
b141e811a   Samuel Ortiz   NFC: llcp: Decrea...
424
  			sk_acceptq_removed(parent);
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
425
426
427
428
429
430
431
432
433
434
  			return sk;
  		}
  
  		release_sock(sk);
  	}
  
  	return NULL;
  }
  
  static int llcp_sock_accept(struct socket *sock, struct socket *newsock,
cdfbabfb2   David Howells   net: Work around ...
435
  			    int flags, bool kern)
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
  {
  	DECLARE_WAITQUEUE(wait, current);
  	struct sock *sk = sock->sk, *new_sk;
  	long timeo;
  	int ret = 0;
  
  	pr_debug("parent %p
  ", sk);
  
  	lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
  
  	if (sk->sk_state != LLCP_LISTEN) {
  		ret = -EBADFD;
  		goto error;
  	}
  
  	timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
  
  	/* Wait for an incoming connection. */
  	add_wait_queue_exclusive(sk_sleep(sk), &wait);
  	while (!(new_sk = nfc_llcp_accept_dequeue(sk, newsock))) {
  		set_current_state(TASK_INTERRUPTIBLE);
  
  		if (!timeo) {
  			ret = -EAGAIN;
  			break;
  		}
  
  		if (signal_pending(current)) {
  			ret = sock_intr_errno(timeo);
  			break;
  		}
  
  		release_sock(sk);
  		timeo = schedule_timeout(timeo);
  		lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
  	}
  	__set_current_state(TASK_RUNNING);
  	remove_wait_queue(sk_sleep(sk), &wait);
  
  	if (ret)
  		goto error;
  
  	newsock->state = SS_CONNECTED;
  
  	pr_debug("new socket %p
  ", new_sk);
  
  error:
  	release_sock(sk);
  
  	return ret;
  }
12e5bdfef   Samuel Ortiz   NFC: Fix LLCP get...
489
  static int llcp_sock_getname(struct socket *sock, struct sockaddr *uaddr,
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
490
491
  			     int *len, int peer)
  {
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
492
493
  	struct sock *sk = sock->sk;
  	struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk);
12e5bdfef   Samuel Ortiz   NFC: Fix LLCP get...
494
  	DECLARE_SOCKADDR(struct sockaddr_nfc_llcp *, llcp_addr, uaddr);
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
495

fe3c094ab   Samuel Ortiz   NFC: Check for ll...
496
497
  	if (llcp_sock == NULL || llcp_sock->dev == NULL)
  		return -EBADFD;
12e5bdfef   Samuel Ortiz   NFC: Fix LLCP get...
498
499
500
  	pr_debug("%p %d %d %d
  ", sk, llcp_sock->target_idx,
  		 llcp_sock->dsap, llcp_sock->ssap);
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
501

5ffedc6ed   Dan Carpenter   NFC: llcp: two bu...
502
  	memset(llcp_addr, 0, sizeof(*llcp_addr));
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
503
  	*len = sizeof(struct sockaddr_nfc_llcp);
03c053555   Cong Wang   NFC: Close a race...
504
505
506
507
508
  	lock_sock(sk);
  	if (!llcp_sock->dev) {
  		release_sock(sk);
  		return -EBADFD;
  	}
5ffedc6ed   Dan Carpenter   NFC: llcp: two bu...
509
  	llcp_addr->sa_family = AF_NFC;
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
510
  	llcp_addr->dev_idx = llcp_sock->dev->idx;
12e5bdfef   Samuel Ortiz   NFC: Fix LLCP get...
511
  	llcp_addr->target_idx = llcp_sock->target_idx;
5ffedc6ed   Dan Carpenter   NFC: llcp: two bu...
512
  	llcp_addr->nfc_protocol = llcp_sock->nfc_protocol;
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
513
514
515
516
  	llcp_addr->dsap = llcp_sock->dsap;
  	llcp_addr->ssap = llcp_sock->ssap;
  	llcp_addr->service_name_len = llcp_sock->service_name_len;
  	memcpy(llcp_addr->service_name, llcp_sock->service_name,
427a2eb1f   Samuel Ortiz   NFC: LLCP code id...
517
  	       llcp_addr->service_name_len);
03c053555   Cong Wang   NFC: Close a race...
518
  	release_sock(sk);
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
519
520
521
522
523
524
  
  	return 0;
  }
  
  static inline unsigned int llcp_accept_poll(struct sock *parent)
  {
413df10bb   Axel Lin   NFC: llcp: Use li...
525
  	struct nfc_llcp_sock *llcp_sock, *parent_sock;
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
526
527
528
  	struct sock *sk;
  
  	parent_sock = nfc_llcp_sock(parent);
413df10bb   Axel Lin   NFC: llcp: Use li...
529
530
  	list_for_each_entry(llcp_sock, &parent_sock->accept_queue,
  			    accept_queue) {
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
531
532
533
534
535
536
537
538
539
540
  		sk = &llcp_sock->sk;
  
  		if (sk->sk_state == LLCP_CONNECTED)
  			return POLLIN | POLLRDNORM;
  	}
  
  	return 0;
  }
  
  static unsigned int llcp_sock_poll(struct file *file, struct socket *sock,
427a2eb1f   Samuel Ortiz   NFC: LLCP code id...
541
  				   poll_table *wait)
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
542
543
544
545
546
547
548
549
550
551
552
553
554
  {
  	struct sock *sk = sock->sk;
  	unsigned int mask = 0;
  
  	pr_debug("%p
  ", sk);
  
  	sock_poll_wait(file, sk_sleep(sk), wait);
  
  	if (sk->sk_state == LLCP_LISTEN)
  		return llcp_accept_poll(sk);
  
  	if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
7d4c04fc1   Keller, Jacob E   net: add option t...
555
  		mask |= POLLERR |
8facd5fb7   Jacob Keller   net: fix smatch w...
556
  			(sock_flag(sk, SOCK_SELECT_ERR_QUEUE) ? POLLPRI : 0);
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
557
558
  
  	if (!skb_queue_empty(&sk->sk_receive_queue))
4260c13ba   Samuel Ortiz   NFC: Update the L...
559
  		mask |= POLLIN | POLLRDNORM;
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
560
561
562
  
  	if (sk->sk_state == LLCP_CLOSED)
  		mask |= POLLHUP;
4260c13ba   Samuel Ortiz   NFC: Update the L...
563
564
565
566
567
  	if (sk->sk_shutdown & RCV_SHUTDOWN)
  		mask |= POLLRDHUP | POLLIN | POLLRDNORM;
  
  	if (sk->sk_shutdown == SHUTDOWN_MASK)
  		mask |= POLLHUP;
b4011239a   Samuel Ortiz   NFC: llcp: Fix no...
568
  	if (sock_writeable(sk) && sk->sk_state == LLCP_CONNECTED)
4260c13ba   Samuel Ortiz   NFC: Update the L...
569
570
  		mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
  	else
9cd3e072b   Eric Dumazet   net: rename SOCK_...
571
  		sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk);
4260c13ba   Samuel Ortiz   NFC: Update the L...
572
573
574
  
  	pr_debug("mask 0x%x
  ", mask);
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
575
576
577
578
579
580
581
582
  	return mask;
  }
  
  static int llcp_sock_release(struct socket *sock)
  {
  	struct sock *sk = sock->sk;
  	struct nfc_llcp_local *local;
  	struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk);
40c75f81d   Samuel Ortiz   NFC: Fix LLCP soc...
583
  	int err = 0;
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
584
585
586
587
588
589
590
591
  
  	if (!sk)
  		return 0;
  
  	pr_debug("%p
  ", sk);
  
  	local = llcp_sock->local;
40c75f81d   Samuel Ortiz   NFC: Fix LLCP soc...
592
593
594
595
  	if (local == NULL) {
  		err = -ENODEV;
  		goto out;
  	}
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
596

d646960f7   Samuel Ortiz   NFC: Initial LLCP...
597
598
599
600
  	lock_sock(sk);
  
  	/* Send a DISC */
  	if (sk->sk_state == LLCP_CONNECTED)
58e3dd155   Thierry Escande   NFC: Rename nfc_l...
601
  		nfc_llcp_send_disconnect(llcp_sock);
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
602
603
604
605
606
607
  
  	if (sk->sk_state == LLCP_LISTEN) {
  		struct nfc_llcp_sock *lsk, *n;
  		struct sock *accept_sk;
  
  		list_for_each_entry_safe(lsk, n, &llcp_sock->accept_queue,
427a2eb1f   Samuel Ortiz   NFC: LLCP code id...
608
  					 accept_queue) {
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
609
610
  			accept_sk = &lsk->sk;
  			lock_sock(accept_sk);
58e3dd155   Thierry Escande   NFC: Rename nfc_l...
611
  			nfc_llcp_send_disconnect(lsk);
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
612
613
614
  			nfc_llcp_accept_unlink(accept_sk);
  
  			release_sock(accept_sk);
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
615
616
  		}
  	}
cbbf47218   Samuel Ortiz   NFC: Release LLCP...
617
618
  	if (llcp_sock->reserved_ssap < LLCP_SAP_MAX)
  		nfc_llcp_put_ssap(llcp_sock->local, llcp_sock->ssap);
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
619

d646960f7   Samuel Ortiz   NFC: Initial LLCP...
620
  	release_sock(sk);
17f7ae16a   Thierry Escande   NFC: Keep socket ...
621
622
623
624
625
626
  	/* Keep this sock alive and therefore do not remove it from the sockets
  	 * list until the DISC PDU has been actually sent. Otherwise we would
  	 * reply with DM PDUs before sending the DISC one.
  	 */
  	if (sk->sk_state == LLCP_DISCONNECTING)
  		return err;
4463523be   Thierry Escande   NFC: LLCP raw soc...
627
628
629
630
  	if (sock->type == SOCK_RAW)
  		nfc_llcp_sock_unlink(&local->raw_sockets, sk);
  	else
  		nfc_llcp_sock_unlink(&local->sockets, sk);
a69f32af8   Samuel Ortiz   NFC: Socket linke...
631

40c75f81d   Samuel Ortiz   NFC: Fix LLCP soc...
632
  out:
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
633
634
  	sock_orphan(sk);
  	sock_put(sk);
40c75f81d   Samuel Ortiz   NFC: Fix LLCP soc...
635
  	return err;
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
636
637
638
  }
  
  static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr,
427a2eb1f   Samuel Ortiz   NFC: LLCP code id...
639
  			     int len, int flags)
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
640
641
642
643
644
645
646
647
648
649
  {
  	struct sock *sk = sock->sk;
  	struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk);
  	struct sockaddr_nfc_llcp *addr = (struct sockaddr_nfc_llcp *)_addr;
  	struct nfc_dev *dev;
  	struct nfc_llcp_local *local;
  	int ret = 0;
  
  	pr_debug("sock %p sk %p flags 0x%x
  ", sock, sk, flags);
608c4adfc   Mateusz Jurczyk   nfc: Fix the sock...
650
  	if (!addr || len < sizeof(*addr) || addr->sa_family != AF_NFC)
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
651
  		return -EINVAL;
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
652

32418cfe4   Dave Jones   Remove noisy prin...
653
  	if (addr->service_name_len == 0 && addr->dsap == 0)
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
654
  		return -EINVAL;
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
655
656
657
  
  	pr_debug("addr dev_idx=%u target_idx=%u protocol=%u
  ", addr->dev_idx,
427a2eb1f   Samuel Ortiz   NFC: LLCP code id...
658
  		 addr->target_idx, addr->nfc_protocol);
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
  
  	lock_sock(sk);
  
  	if (sk->sk_state == LLCP_CONNECTED) {
  		ret = -EISCONN;
  		goto error;
  	}
  
  	dev = nfc_get_device(addr->dev_idx);
  	if (dev == NULL) {
  		ret = -ENODEV;
  		goto error;
  	}
  
  	local = nfc_llcp_find_local(dev);
  	if (local == NULL) {
  		ret = -ENODEV;
  		goto put_dev;
  	}
  
  	device_lock(&dev->dev);
  	if (dev->dep_link_up == false) {
  		ret = -ENOLINK;
  		device_unlock(&dev->dev);
  		goto put_dev;
  	}
  	device_unlock(&dev->dev);
  
  	if (local->rf_mode == NFC_RF_INITIATOR &&
427a2eb1f   Samuel Ortiz   NFC: LLCP code id...
688
  	    addr->target_idx != local->target_idx) {
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
689
690
691
692
693
  		ret = -ENOLINK;
  		goto put_dev;
  	}
  
  	llcp_sock->dev = dev;
c7aa12252   Samuel Ortiz   NFC: Take a refer...
694
  	llcp_sock->local = nfc_llcp_local_get(local);
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
695
696
697
698
699
  	llcp_sock->ssap = nfc_llcp_get_local_ssap(local);
  	if (llcp_sock->ssap == LLCP_SAP_MAX) {
  		ret = -ENOMEM;
  		goto put_dev;
  	}
cbbf47218   Samuel Ortiz   NFC: Release LLCP...
700
701
  
  	llcp_sock->reserved_ssap = llcp_sock->ssap;
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
702
703
704
705
706
707
  	if (addr->service_name_len == 0)
  		llcp_sock->dsap = addr->dsap;
  	else
  		llcp_sock->dsap = LLCP_SAP_SDP;
  	llcp_sock->nfc_protocol = addr->nfc_protocol;
  	llcp_sock->service_name_len = min_t(unsigned int,
427a2eb1f   Samuel Ortiz   NFC: LLCP code id...
708
709
  					    addr->service_name_len,
  					    NFC_LLCP_MAX_SERVICE_NAME);
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
710
  	llcp_sock->service_name = kmemdup(addr->service_name,
427a2eb1f   Samuel Ortiz   NFC: LLCP code id...
711
712
  					  llcp_sock->service_name_len,
  					  GFP_KERNEL);
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
713

a69f32af8   Samuel Ortiz   NFC: Socket linke...
714
  	nfc_llcp_sock_link(&local->connecting_sockets, sk);
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
715
716
717
  
  	ret = nfc_llcp_send_connect(llcp_sock);
  	if (ret)
a69f32af8   Samuel Ortiz   NFC: Socket linke...
718
  		goto sock_unlink;
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
719

b4011239a   Samuel Ortiz   NFC: llcp: Fix no...
720
  	sk->sk_state = LLCP_CONNECTING;
ff353d86a   Samuel Ortiz   NFC: LLCP connect...
721
722
  	ret = sock_wait_state(sk, LLCP_CONNECTED,
  			      sock_sndtimeo(sk, flags & O_NONBLOCK));
b4011239a   Samuel Ortiz   NFC: llcp: Fix no...
723
  	if (ret && ret != -EINPROGRESS)
a69f32af8   Samuel Ortiz   NFC: Socket linke...
724
  		goto sock_unlink;
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
725
726
  
  	release_sock(sk);
ff353d86a   Samuel Ortiz   NFC: LLCP connect...
727

b4011239a   Samuel Ortiz   NFC: llcp: Fix no...
728
  	return ret;
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
729

a69f32af8   Samuel Ortiz   NFC: Socket linke...
730
731
732
733
  sock_unlink:
  	nfc_llcp_put_ssap(local, llcp_sock->ssap);
  
  	nfc_llcp_sock_unlink(&local->connecting_sockets, sk);
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
734
735
736
737
738
739
740
  put_dev:
  	nfc_put_device(dev);
  
  error:
  	release_sock(sk);
  	return ret;
  }
1b7841404   Ying Xue   net: Remove iocb ...
741
742
  static int llcp_sock_sendmsg(struct socket *sock, struct msghdr *msg,
  			     size_t len)
53a0ac2ee   Samuel Ortiz   NFC: LLCP socket ...
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
  {
  	struct sock *sk = sock->sk;
  	struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk);
  	int ret;
  
  	pr_debug("sock %p sk %p", sock, sk);
  
  	ret = sock_error(sk);
  	if (ret)
  		return ret;
  
  	if (msg->msg_flags & MSG_OOB)
  		return -EOPNOTSUPP;
  
  	lock_sock(sk);
b874dec21   Samuel Ortiz   NFC: Implement LL...
758
  	if (sk->sk_type == SOCK_DGRAM) {
342dfc306   Steffen Hurrle   net: add build-ti...
759
760
  		DECLARE_SOCKADDR(struct sockaddr_nfc_llcp *, addr,
  				 msg->msg_name);
b874dec21   Samuel Ortiz   NFC: Implement LL...
761
762
763
  
  		if (msg->msg_namelen < sizeof(*addr)) {
  			release_sock(sk);
b874dec21   Samuel Ortiz   NFC: Implement LL...
764
765
766
767
768
769
770
771
  			return -EINVAL;
  		}
  
  		release_sock(sk);
  
  		return nfc_llcp_send_ui_frame(llcp_sock, addr->dsap, addr->ssap,
  					      msg, len);
  	}
53a0ac2ee   Samuel Ortiz   NFC: LLCP socket ...
772
773
774
775
776
777
778
779
780
  	if (sk->sk_state != LLCP_CONNECTED) {
  		release_sock(sk);
  		return -ENOTCONN;
  	}
  
  	release_sock(sk);
  
  	return nfc_llcp_send_i_frame(llcp_sock, msg, len);
  }
1b7841404   Ying Xue   net: Remove iocb ...
781
782
  static int llcp_sock_recvmsg(struct socket *sock, struct msghdr *msg,
  			     size_t len, int flags)
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
783
784
785
786
787
788
789
790
791
792
793
794
795
  {
  	int noblock = flags & MSG_DONTWAIT;
  	struct sock *sk = sock->sk;
  	unsigned int copied, rlen;
  	struct sk_buff *skb, *cskb;
  	int err = 0;
  
  	pr_debug("%p %zu
  ", sk, len);
  
  	lock_sock(sk);
  
  	if (sk->sk_state == LLCP_CLOSED &&
427a2eb1f   Samuel Ortiz   NFC: LLCP code id...
796
  	    skb_queue_empty(&sk->sk_receive_queue)) {
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
797
798
799
800
801
802
803
804
805
806
807
808
  		release_sock(sk);
  		return 0;
  	}
  
  	release_sock(sk);
  
  	if (flags & (MSG_OOB))
  		return -EOPNOTSUPP;
  
  	skb = skb_recv_datagram(sk, flags, noblock, &err);
  	if (!skb) {
  		pr_err("Recv datagram failed state %d %d %d",
427a2eb1f   Samuel Ortiz   NFC: LLCP code id...
809
  		       sk->sk_state, err, sock_error(sk));
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
810
811
812
813
814
815
  
  		if (sk->sk_shutdown & RCV_SHUTDOWN)
  			return 0;
  
  		return err;
  	}
427a2eb1f   Samuel Ortiz   NFC: LLCP code id...
816
  	rlen = skb->len;		/* real length of skb */
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
817
818
819
  	copied = min_t(unsigned int, rlen, len);
  
  	cskb = skb;
51f3d02b9   David S. Miller   net: Add and use ...
820
  	if (skb_copy_datagram_msg(cskb, 0, msg, copied)) {
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
821
822
823
824
  		if (!(flags & MSG_PEEK))
  			skb_queue_head(&sk->sk_receive_queue, skb);
  		return -EFAULT;
  	}
2c2d45bdc   Thierry Escande   NFC: Add support ...
825
  	sock_recv_timestamp(msg, sk, skb);
31ca61a8d   Samuel Ortiz   NFC: Forward LLCP...
826
827
  	if (sk->sk_type == SOCK_DGRAM && msg->msg_name) {
  		struct nfc_llcp_ui_cb *ui_cb = nfc_llcp_ui_skb_cb(skb);
342dfc306   Steffen Hurrle   net: add build-ti...
828
829
  		DECLARE_SOCKADDR(struct sockaddr_nfc_llcp *, sockaddr,
  				 msg->msg_name);
31ca61a8d   Samuel Ortiz   NFC: Forward LLCP...
830

fad2e371b   Samuel Ortiz   NFC: Avoid memcpy...
831
  		msg->msg_namelen = sizeof(struct sockaddr_nfc_llcp);
31ca61a8d   Samuel Ortiz   NFC: Forward LLCP...
832

fad2e371b   Samuel Ortiz   NFC: Avoid memcpy...
833
834
  		pr_debug("Datagram socket %d %d
  ", ui_cb->dsap, ui_cb->ssap);
31ca61a8d   Samuel Ortiz   NFC: Forward LLCP...
835

d26d6504f   Mathias Krause   NFC: llcp: fix in...
836
  		memset(sockaddr, 0, sizeof(*sockaddr));
fad2e371b   Samuel Ortiz   NFC: Avoid memcpy...
837
838
839
840
  		sockaddr->sa_family = AF_NFC;
  		sockaddr->nfc_protocol = NFC_PROTO_NFC_DEP;
  		sockaddr->dsap = ui_cb->dsap;
  		sockaddr->ssap = ui_cb->ssap;
31ca61a8d   Samuel Ortiz   NFC: Forward LLCP...
841
  	}
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
842
843
844
845
  	/* Mark read part of skb as used */
  	if (!(flags & MSG_PEEK)) {
  
  		/* SOCK_STREAM: re-queue skb if it contains unreceived data */
31ca61a8d   Samuel Ortiz   NFC: Forward LLCP...
846
847
848
  		if (sk->sk_type == SOCK_STREAM ||
  		    sk->sk_type == SOCK_DGRAM ||
  		    sk->sk_type == SOCK_RAW) {
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
  			skb_pull(skb, copied);
  			if (skb->len) {
  				skb_queue_head(&sk->sk_receive_queue, skb);
  				goto done;
  			}
  		}
  
  		kfree_skb(skb);
  	}
  
  	/* XXX Queue backlogged skbs */
  
  done:
  	/* SOCK_SEQPACKET: return real length if MSG_TRUNC is set */
  	if (sk->sk_type == SOCK_SEQPACKET && (flags & MSG_TRUNC))
  		copied = rlen;
  
  	return copied;
  }
  
  static const struct proto_ops llcp_sock_ops = {
  	.family         = PF_NFC,
  	.owner          = THIS_MODULE,
  	.bind           = llcp_sock_bind,
  	.connect        = llcp_sock_connect,
  	.release        = llcp_sock_release,
  	.socketpair     = sock_no_socketpair,
  	.accept         = llcp_sock_accept,
  	.getname        = llcp_sock_getname,
  	.poll           = llcp_sock_poll,
  	.ioctl          = sock_no_ioctl,
  	.listen         = llcp_sock_listen,
  	.shutdown       = sock_no_shutdown,
26fd76cab   Samuel Ortiz   NFC: llcp: Implem...
882
883
  	.setsockopt     = nfc_llcp_setsockopt,
  	.getsockopt     = nfc_llcp_getsockopt,
53a0ac2ee   Samuel Ortiz   NFC: LLCP socket ...
884
  	.sendmsg        = llcp_sock_sendmsg,
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
885
886
887
  	.recvmsg        = llcp_sock_recvmsg,
  	.mmap           = sock_no_mmap,
  };
4463523be   Thierry Escande   NFC: LLCP raw soc...
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
  static const struct proto_ops llcp_rawsock_ops = {
  	.family         = PF_NFC,
  	.owner          = THIS_MODULE,
  	.bind           = llcp_raw_sock_bind,
  	.connect        = sock_no_connect,
  	.release        = llcp_sock_release,
  	.socketpair     = sock_no_socketpair,
  	.accept         = sock_no_accept,
  	.getname        = llcp_sock_getname,
  	.poll           = llcp_sock_poll,
  	.ioctl          = sock_no_ioctl,
  	.listen         = sock_no_listen,
  	.shutdown       = sock_no_shutdown,
  	.setsockopt     = sock_no_setsockopt,
  	.getsockopt     = sock_no_getsockopt,
  	.sendmsg        = sock_no_sendmsg,
  	.recvmsg        = llcp_sock_recvmsg,
  	.mmap           = sock_no_mmap,
  };
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
  static void llcp_sock_destruct(struct sock *sk)
  {
  	struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk);
  
  	pr_debug("%p
  ", sk);
  
  	if (sk->sk_state == LLCP_CONNECTED)
  		nfc_put_device(llcp_sock->dev);
  
  	skb_queue_purge(&sk->sk_receive_queue);
  
  	nfc_llcp_sock_free(llcp_sock);
  
  	if (!sock_flag(sk, SOCK_DEAD)) {
  		pr_err("Freeing alive NFC LLCP socket %p
  ", sk);
  		return;
  	}
  }
11aa9c28b   Eric W. Biederman   net: Pass kern fr...
927
  struct sock *nfc_llcp_sock_alloc(struct socket *sock, int type, gfp_t gfp, int kern)
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
928
929
930
  {
  	struct sock *sk;
  	struct nfc_llcp_sock *llcp_sock;
11aa9c28b   Eric W. Biederman   net: Pass kern fr...
931
  	sk = sk_alloc(&init_net, PF_NFC, gfp, &llcp_sock_proto, kern);
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
932
933
934
935
936
937
938
939
940
941
942
943
944
  	if (!sk)
  		return NULL;
  
  	llcp_sock = nfc_llcp_sock(sk);
  
  	sock_init_data(sock, sk);
  	sk->sk_state = LLCP_CLOSED;
  	sk->sk_protocol = NFC_SOCKPROTO_LLCP;
  	sk->sk_type = type;
  	sk->sk_destruct = llcp_sock_destruct;
  
  	llcp_sock->ssap = 0;
  	llcp_sock->dsap = LLCP_SAP_SDP;
06d44f806   Samuel Ortiz   NFC: llcp: Use so...
945
  	llcp_sock->rw = LLCP_MAX_RW + 1;
5eef66697   Samuel Ortiz   NFC: llcp: Socket...
946
  	llcp_sock->miux = cpu_to_be16(LLCP_MAX_MIUX + 1);
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
947
948
949
  	llcp_sock->send_n = llcp_sock->send_ack_n = 0;
  	llcp_sock->recv_n = llcp_sock->recv_ack_n = 0;
  	llcp_sock->remote_ready = 1;
cbbf47218   Samuel Ortiz   NFC: Release LLCP...
950
  	llcp_sock->reserved_ssap = LLCP_SAP_MAX;
abd18d433   Thierry Escande   NFC: llcp: Reset ...
951
  	nfc_llcp_socket_remote_param_init(llcp_sock);
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
952
953
  	skb_queue_head_init(&llcp_sock->tx_queue);
  	skb_queue_head_init(&llcp_sock->tx_pending_queue);
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
954
955
956
957
958
959
960
961
962
963
964
965
966
967
  	INIT_LIST_HEAD(&llcp_sock->accept_queue);
  
  	if (sock != NULL)
  		sock->state = SS_UNCONNECTED;
  
  	return sk;
  }
  
  void nfc_llcp_sock_free(struct nfc_llcp_sock *sock)
  {
  	kfree(sock->service_name);
  
  	skb_queue_purge(&sock->tx_queue);
  	skb_queue_purge(&sock->tx_pending_queue);
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
968
969
  
  	list_del_init(&sock->accept_queue);
40c75f81d   Samuel Ortiz   NFC: Fix LLCP soc...
970

d646960f7   Samuel Ortiz   NFC: Initial LLCP...
971
  	sock->parent = NULL;
c7aa12252   Samuel Ortiz   NFC: Take a refer...
972
973
  
  	nfc_llcp_local_put(sock->local);
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
974
975
976
  }
  
  static int llcp_sock_create(struct net *net, struct socket *sock,
11aa9c28b   Eric W. Biederman   net: Pass kern fr...
977
  			    const struct nfc_protocol *nfc_proto, int kern)
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
978
979
980
981
982
  {
  	struct sock *sk;
  
  	pr_debug("%p
  ", sock);
4463523be   Thierry Escande   NFC: LLCP raw soc...
983
984
985
  	if (sock->type != SOCK_STREAM &&
  	    sock->type != SOCK_DGRAM &&
  	    sock->type != SOCK_RAW)
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
986
  		return -ESOCKTNOSUPPORT;
4463523be   Thierry Escande   NFC: LLCP raw soc...
987
988
989
990
  	if (sock->type == SOCK_RAW)
  		sock->ops = &llcp_rawsock_ops;
  	else
  		sock->ops = &llcp_sock_ops;
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
991

11aa9c28b   Eric W. Biederman   net: Pass kern fr...
992
  	sk = nfc_llcp_sock_alloc(sock, sock->type, GFP_ATOMIC, kern);
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
  	if (sk == NULL)
  		return -ENOMEM;
  
  	return 0;
  }
  
  static const struct nfc_protocol llcp_nfc_proto = {
  	.id	  = NFC_SOCKPROTO_LLCP,
  	.proto    = &llcp_sock_proto,
  	.owner    = THIS_MODULE,
  	.create   = llcp_sock_create
  };
  
  int __init nfc_llcp_sock_init(void)
  {
  	return nfc_proto_register(&llcp_nfc_proto);
  }
  
  void nfc_llcp_sock_exit(void)
  {
  	nfc_proto_unregister(&llcp_nfc_proto);
  }