Blame view

net/nfc/rawsock.c 9.56 KB
23b7869c0   Lauro Ramos Venancio   NFC: add the NFC ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  /*
   * Copyright (C) 2011 Instituto Nokia de Tecnologia
   *
   * Authors:
   *    Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
   *    Lauro Ramos Venancio <lauro.venancio@openbossa.org>
   *
   * 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...
19
   * along with this program; if not, see <http://www.gnu.org/licenses/>.
23b7869c0   Lauro Ramos Venancio   NFC: add the NFC ...
20
   */
52858b51b   Samuel Ortiz   NFC: Add function...
21
  #define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__
ed1e0ad88   Joe Perches   nfc: Use standard...
22

23b7869c0   Lauro Ramos Venancio   NFC: add the NFC ...
23
24
  #include <net/tcp_states.h>
  #include <linux/nfc.h>
bc3b2d7fb   Paul Gortmaker   net: Add export.h...
25
  #include <linux/export.h>
23b7869c0   Lauro Ramos Venancio   NFC: add the NFC ...
26
27
  
  #include "nfc.h"
57be1f3f3   Hiren Tandel   NFC: Add RAW sock...
28
29
30
  static struct nfc_sock_list raw_sk_list = {
  	.lock = __RW_LOCK_UNLOCKED(raw_sk_list.lock)
  };
db3287da3   Fengguang Wu   NFC: nfc_sock_lin...
31
  static void nfc_sock_link(struct nfc_sock_list *l, struct sock *sk)
57be1f3f3   Hiren Tandel   NFC: Add RAW sock...
32
33
34
35
36
  {
  	write_lock(&l->lock);
  	sk_add_node(sk, &l->head);
  	write_unlock(&l->lock);
  }
db3287da3   Fengguang Wu   NFC: nfc_sock_lin...
37
  static void nfc_sock_unlink(struct nfc_sock_list *l, struct sock *sk)
57be1f3f3   Hiren Tandel   NFC: Add RAW sock...
38
39
40
41
42
  {
  	write_lock(&l->lock);
  	sk_del_node_init(sk);
  	write_unlock(&l->lock);
  }
23b7869c0   Lauro Ramos Venancio   NFC: add the NFC ...
43
44
  static void rawsock_write_queue_purge(struct sock *sk)
  {
20c239c13   Joe Perches   nfc: Convert nfc_...
45
46
  	pr_debug("sk=%p
  ", sk);
23b7869c0   Lauro Ramos Venancio   NFC: add the NFC ...
47
48
49
50
51
52
53
54
55
  
  	spin_lock_bh(&sk->sk_write_queue.lock);
  	__skb_queue_purge(&sk->sk_write_queue);
  	nfc_rawsock(sk)->tx_work_scheduled = false;
  	spin_unlock_bh(&sk->sk_write_queue.lock);
  }
  
  static void rawsock_report_error(struct sock *sk, int err)
  {
20c239c13   Joe Perches   nfc: Convert nfc_...
56
57
  	pr_debug("sk=%p err=%d
  ", sk, err);
23b7869c0   Lauro Ramos Venancio   NFC: add the NFC ...
58
59
60
61
62
63
64
65
66
67
68
  
  	sk->sk_shutdown = SHUTDOWN_MASK;
  	sk->sk_err = -err;
  	sk->sk_error_report(sk);
  
  	rawsock_write_queue_purge(sk);
  }
  
  static int rawsock_release(struct socket *sock)
  {
  	struct sock *sk = sock->sk;
03e934f62   Eric Dumazet   NFC: Return from ...
69
70
71
72
73
  	pr_debug("sock=%p sk=%p
  ", sock, sk);
  
  	if (!sk)
  		return 0;
23b7869c0   Lauro Ramos Venancio   NFC: add the NFC ...
74

57be1f3f3   Hiren Tandel   NFC: Add RAW sock...
75
76
  	if (sock->type == SOCK_RAW)
  		nfc_sock_unlink(&raw_sk_list, sk);
23b7869c0   Lauro Ramos Venancio   NFC: add the NFC ...
77
78
79
80
81
82
83
  	sock_orphan(sk);
  	sock_put(sk);
  
  	return 0;
  }
  
  static int rawsock_connect(struct socket *sock, struct sockaddr *_addr,
0a40acb24   Samuel Ortiz   NFC: Core code id...
84
  			   int len, int flags)
23b7869c0   Lauro Ramos Venancio   NFC: add the NFC ...
85
86
87
88
89
  {
  	struct sock *sk = sock->sk;
  	struct sockaddr_nfc *addr = (struct sockaddr_nfc *)_addr;
  	struct nfc_dev *dev;
  	int rc = 0;
20c239c13   Joe Perches   nfc: Convert nfc_...
90
91
  	pr_debug("sock=%p sk=%p flags=%d
  ", sock, sk, flags);
23b7869c0   Lauro Ramos Venancio   NFC: add the NFC ...
92
93
  
  	if (!addr || len < sizeof(struct sockaddr_nfc) ||
0a40acb24   Samuel Ortiz   NFC: Core code id...
94
  	    addr->sa_family != AF_NFC)
23b7869c0   Lauro Ramos Venancio   NFC: add the NFC ...
95
  		return -EINVAL;
20c239c13   Joe Perches   nfc: Convert nfc_...
96
97
98
  	pr_debug("addr dev_idx=%u target_idx=%u protocol=%u
  ",
  		 addr->dev_idx, addr->target_idx, addr->nfc_protocol);
23b7869c0   Lauro Ramos Venancio   NFC: add the NFC ...
99
100
101
102
103
104
105
106
107
108
109
110
111
  
  	lock_sock(sk);
  
  	if (sock->state == SS_CONNECTED) {
  		rc = -EISCONN;
  		goto error;
  	}
  
  	dev = nfc_get_device(addr->dev_idx);
  	if (!dev) {
  		rc = -ENODEV;
  		goto error;
  	}
01ae0eea9   Eric Lapuyade   NFC: Fix next tar...
112
113
  	if (addr->target_idx > dev->target_next_idx - 1 ||
  	    addr->target_idx < dev->target_next_idx - dev->n_targets) {
c4fbb6515   Samuel Ortiz   NFC: The core par...
114
115
116
  		rc = -EINVAL;
  		goto error;
  	}
23b7869c0   Lauro Ramos Venancio   NFC: add the NFC ...
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
  	rc = nfc_activate_target(dev, addr->target_idx, addr->nfc_protocol);
  	if (rc)
  		goto put_dev;
  
  	nfc_rawsock(sk)->dev = dev;
  	nfc_rawsock(sk)->target_idx = addr->target_idx;
  	sock->state = SS_CONNECTED;
  	sk->sk_state = TCP_ESTABLISHED;
  	sk->sk_state_change(sk);
  
  	release_sock(sk);
  	return 0;
  
  put_dev:
  	nfc_put_device(dev);
  error:
  	release_sock(sk);
  	return rc;
  }
  
  static int rawsock_add_header(struct sk_buff *skb)
  {
e8753043f   Samuel Ortiz   NFC: Reserve tx h...
139
  	*skb_push(skb, NFC_HEADER_SIZE) = 0;
23b7869c0   Lauro Ramos Venancio   NFC: add the NFC ...
140
141
142
143
144
  
  	return 0;
  }
  
  static void rawsock_data_exchange_complete(void *context, struct sk_buff *skb,
0a40acb24   Samuel Ortiz   NFC: Core code id...
145
  					   int err)
23b7869c0   Lauro Ramos Venancio   NFC: add the NFC ...
146
147
148
149
  {
  	struct sock *sk = (struct sock *) context;
  
  	BUG_ON(in_irq());
20c239c13   Joe Perches   nfc: Convert nfc_...
150
151
  	pr_debug("sk=%p err=%d
  ", sk, err);
23b7869c0   Lauro Ramos Venancio   NFC: add the NFC ...
152
153
154
155
156
157
  
  	if (err)
  		goto error;
  
  	err = rawsock_add_header(skb);
  	if (err)
4cf7e0329   Thierry Escande   NFC: rawsock: Fix...
158
  		goto error_skb;
23b7869c0   Lauro Ramos Venancio   NFC: add the NFC ...
159
160
161
  
  	err = sock_queue_rcv_skb(sk, skb);
  	if (err)
4cf7e0329   Thierry Escande   NFC: rawsock: Fix...
162
  		goto error_skb;
23b7869c0   Lauro Ramos Venancio   NFC: add the NFC ...
163
164
165
166
167
168
169
170
171
172
  
  	spin_lock_bh(&sk->sk_write_queue.lock);
  	if (!skb_queue_empty(&sk->sk_write_queue))
  		schedule_work(&nfc_rawsock(sk)->tx_work);
  	else
  		nfc_rawsock(sk)->tx_work_scheduled = false;
  	spin_unlock_bh(&sk->sk_write_queue.lock);
  
  	sock_put(sk);
  	return;
4cf7e0329   Thierry Escande   NFC: rawsock: Fix...
173
174
  error_skb:
  	kfree_skb(skb);
23b7869c0   Lauro Ramos Venancio   NFC: add the NFC ...
175
176
177
178
179
180
181
182
183
184
185
186
  error:
  	rawsock_report_error(sk, err);
  	sock_put(sk);
  }
  
  static void rawsock_tx_work(struct work_struct *work)
  {
  	struct sock *sk = to_rawsock_sk(work);
  	struct nfc_dev *dev = nfc_rawsock(sk)->dev;
  	u32 target_idx = nfc_rawsock(sk)->target_idx;
  	struct sk_buff *skb;
  	int rc;
20c239c13   Joe Perches   nfc: Convert nfc_...
187
188
  	pr_debug("sk=%p target_idx=%u
  ", sk, target_idx);
23b7869c0   Lauro Ramos Venancio   NFC: add the NFC ...
189
190
191
192
193
194
195
196
197
198
  
  	if (sk->sk_shutdown & SEND_SHUTDOWN) {
  		rawsock_write_queue_purge(sk);
  		return;
  	}
  
  	skb = skb_dequeue(&sk->sk_write_queue);
  
  	sock_hold(sk);
  	rc = nfc_data_exchange(dev, target_idx, skb,
0a40acb24   Samuel Ortiz   NFC: Core code id...
199
  			       rawsock_data_exchange_complete, sk);
23b7869c0   Lauro Ramos Venancio   NFC: add the NFC ...
200
201
202
203
204
205
206
  	if (rc) {
  		rawsock_report_error(sk, rc);
  		sock_put(sk);
  	}
  }
  
  static int rawsock_sendmsg(struct kiocb *iocb, struct socket *sock,
0a40acb24   Samuel Ortiz   NFC: Core code id...
207
  			   struct msghdr *msg, size_t len)
23b7869c0   Lauro Ramos Venancio   NFC: add the NFC ...
208
209
  {
  	struct sock *sk = sock->sk;
e8753043f   Samuel Ortiz   NFC: Reserve tx h...
210
  	struct nfc_dev *dev = nfc_rawsock(sk)->dev;
23b7869c0   Lauro Ramos Venancio   NFC: add the NFC ...
211
212
  	struct sk_buff *skb;
  	int rc;
20c239c13   Joe Perches   nfc: Convert nfc_...
213
214
  	pr_debug("sock=%p sk=%p len=%zu
  ", sock, sk, len);
23b7869c0   Lauro Ramos Venancio   NFC: add the NFC ...
215
216
217
218
219
220
  
  	if (msg->msg_namelen)
  		return -EOPNOTSUPP;
  
  	if (sock->state != SS_CONNECTED)
  		return -ENOTCONN;
7c7cd3bfe   Samuel Ortiz   NFC: Add tx skb a...
221
222
  	skb = nfc_alloc_send_skb(dev, sk, msg->msg_flags, len, &rc);
  	if (skb == NULL)
23b7869c0   Lauro Ramos Venancio   NFC: add the NFC ...
223
  		return rc;
6ce8e9ce5   Al Viro   new helper: memcp...
224
  	rc = memcpy_from_msg(skb_put(skb, len), msg, len);
23b7869c0   Lauro Ramos Venancio   NFC: add the NFC ...
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
  	if (rc < 0) {
  		kfree_skb(skb);
  		return rc;
  	}
  
  	spin_lock_bh(&sk->sk_write_queue.lock);
  	__skb_queue_tail(&sk->sk_write_queue, skb);
  	if (!nfc_rawsock(sk)->tx_work_scheduled) {
  		schedule_work(&nfc_rawsock(sk)->tx_work);
  		nfc_rawsock(sk)->tx_work_scheduled = true;
  	}
  	spin_unlock_bh(&sk->sk_write_queue.lock);
  
  	return len;
  }
  
  static int rawsock_recvmsg(struct kiocb *iocb, struct socket *sock,
0a40acb24   Samuel Ortiz   NFC: Core code id...
242
  			   struct msghdr *msg, size_t len, int flags)
23b7869c0   Lauro Ramos Venancio   NFC: add the NFC ...
243
244
245
246
247
248
  {
  	int noblock = flags & MSG_DONTWAIT;
  	struct sock *sk = sock->sk;
  	struct sk_buff *skb;
  	int copied;
  	int rc;
20c239c13   Joe Perches   nfc: Convert nfc_...
249
250
  	pr_debug("sock=%p sk=%p len=%zu flags=%d
  ", sock, sk, len, flags);
23b7869c0   Lauro Ramos Venancio   NFC: add the NFC ...
251
252
253
254
  
  	skb = skb_recv_datagram(sk, flags, noblock, &rc);
  	if (!skb)
  		return rc;
23b7869c0   Lauro Ramos Venancio   NFC: add the NFC ...
255
256
257
258
259
  	copied = skb->len;
  	if (len < copied) {
  		msg->msg_flags |= MSG_TRUNC;
  		copied = len;
  	}
51f3d02b9   David S. Miller   net: Add and use ...
260
  	rc = skb_copy_datagram_msg(skb, 0, msg, copied);
23b7869c0   Lauro Ramos Venancio   NFC: add the NFC ...
261
262
263
264
265
  
  	skb_free_datagram(sk, skb);
  
  	return rc ? : copied;
  }
23b7869c0   Lauro Ramos Venancio   NFC: add the NFC ...
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
  static const struct proto_ops rawsock_ops = {
  	.family         = PF_NFC,
  	.owner          = THIS_MODULE,
  	.release        = rawsock_release,
  	.bind           = sock_no_bind,
  	.connect        = rawsock_connect,
  	.socketpair     = sock_no_socketpair,
  	.accept         = sock_no_accept,
  	.getname        = sock_no_getname,
  	.poll           = datagram_poll,
  	.ioctl          = sock_no_ioctl,
  	.listen         = sock_no_listen,
  	.shutdown       = sock_no_shutdown,
  	.setsockopt     = sock_no_setsockopt,
  	.getsockopt     = sock_no_getsockopt,
  	.sendmsg        = rawsock_sendmsg,
  	.recvmsg        = rawsock_recvmsg,
  	.mmap           = sock_no_mmap,
  };
57be1f3f3   Hiren Tandel   NFC: Add RAW sock...
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
  static const struct proto_ops rawsock_raw_ops = {
  	.family         = PF_NFC,
  	.owner          = THIS_MODULE,
  	.release        = rawsock_release,
  	.bind           = sock_no_bind,
  	.connect        = sock_no_connect,
  	.socketpair     = sock_no_socketpair,
  	.accept         = sock_no_accept,
  	.getname        = sock_no_getname,
  	.poll           = datagram_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        = rawsock_recvmsg,
  	.mmap           = sock_no_mmap,
  };
23b7869c0   Lauro Ramos Venancio   NFC: add the NFC ...
304
305
  static void rawsock_destruct(struct sock *sk)
  {
20c239c13   Joe Perches   nfc: Convert nfc_...
306
307
  	pr_debug("sk=%p
  ", sk);
23b7869c0   Lauro Ramos Venancio   NFC: add the NFC ...
308
309
310
  
  	if (sk->sk_state == TCP_ESTABLISHED) {
  		nfc_deactivate_target(nfc_rawsock(sk)->dev,
0a40acb24   Samuel Ortiz   NFC: Core code id...
311
  				      nfc_rawsock(sk)->target_idx);
23b7869c0   Lauro Ramos Venancio   NFC: add the NFC ...
312
313
314
315
316
317
  		nfc_put_device(nfc_rawsock(sk)->dev);
  	}
  
  	skb_queue_purge(&sk->sk_receive_queue);
  
  	if (!sock_flag(sk, SOCK_DEAD)) {
ed1e0ad88   Joe Perches   nfc: Use standard...
318
319
  		pr_err("Freeing alive NFC raw socket %p
  ", sk);
23b7869c0   Lauro Ramos Venancio   NFC: add the NFC ...
320
321
322
323
324
  		return;
  	}
  }
  
  static int rawsock_create(struct net *net, struct socket *sock,
0a40acb24   Samuel Ortiz   NFC: Core code id...
325
  			  const struct nfc_protocol *nfc_proto)
23b7869c0   Lauro Ramos Venancio   NFC: add the NFC ...
326
327
  {
  	struct sock *sk;
20c239c13   Joe Perches   nfc: Convert nfc_...
328
329
  	pr_debug("sock=%p
  ", sock);
23b7869c0   Lauro Ramos Venancio   NFC: add the NFC ...
330

57be1f3f3   Hiren Tandel   NFC: Add RAW sock...
331
  	if ((sock->type != SOCK_SEQPACKET) && (sock->type != SOCK_RAW))
23b7869c0   Lauro Ramos Venancio   NFC: add the NFC ...
332
  		return -ESOCKTNOSUPPORT;
57be1f3f3   Hiren Tandel   NFC: Add RAW sock...
333
334
335
336
  	if (sock->type == SOCK_RAW)
  		sock->ops = &rawsock_raw_ops;
  	else
  		sock->ops = &rawsock_ops;
23b7869c0   Lauro Ramos Venancio   NFC: add the NFC ...
337

db81a6245   Samuel Ortiz   NFC: Atomic socke...
338
  	sk = sk_alloc(net, PF_NFC, GFP_ATOMIC, nfc_proto->proto);
23b7869c0   Lauro Ramos Venancio   NFC: add the NFC ...
339
340
341
342
343
344
345
  	if (!sk)
  		return -ENOMEM;
  
  	sock_init_data(sock, sk);
  	sk->sk_protocol = nfc_proto->id;
  	sk->sk_destruct = rawsock_destruct;
  	sock->state = SS_UNCONNECTED;
57be1f3f3   Hiren Tandel   NFC: Add RAW sock...
346
347
348
349
350
351
  	if (sock->type == SOCK_RAW)
  		nfc_sock_link(&raw_sk_list, sk);
  	else {
  		INIT_WORK(&nfc_rawsock(sk)->tx_work, rawsock_tx_work);
  		nfc_rawsock(sk)->tx_work_scheduled = false;
  	}
23b7869c0   Lauro Ramos Venancio   NFC: add the NFC ...
352
353
354
  
  	return 0;
  }
57be1f3f3   Hiren Tandel   NFC: Add RAW sock...
355
356
357
358
359
360
361
362
363
364
365
  void nfc_send_to_raw_sock(struct nfc_dev *dev, struct sk_buff *skb,
  			  u8 payload_type, u8 direction)
  {
  	struct sk_buff *skb_copy = NULL, *nskb;
  	struct sock *sk;
  	u8 *data;
  
  	read_lock(&raw_sk_list.lock);
  
  	sk_for_each(sk, &raw_sk_list.head) {
  		if (!skb_copy) {
bad93e9d4   Octavian Purdila   net: add __pskb_c...
366
367
  			skb_copy = __pskb_copy_fclone(skb, NFC_RAW_HEADER_SIZE,
  						      GFP_ATOMIC, true);
57be1f3f3   Hiren Tandel   NFC: Add RAW sock...
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
  			if (!skb_copy)
  				continue;
  
  			data = skb_push(skb_copy, NFC_RAW_HEADER_SIZE);
  
  			data[0] = dev ? dev->idx : 0xFF;
  			data[1] = direction & 0x01;
  			data[1] |= (payload_type << 1);
  		}
  
  		nskb = skb_clone(skb_copy, GFP_ATOMIC);
  		if (!nskb)
  			continue;
  
  		if (sock_queue_rcv_skb(sk, nskb))
  			kfree_skb(nskb);
  	}
  
  	read_unlock(&raw_sk_list.lock);
  
  	kfree_skb(skb_copy);
  }
  EXPORT_SYMBOL(nfc_send_to_raw_sock);
23b7869c0   Lauro Ramos Venancio   NFC: add the NFC ...
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
  static struct proto rawsock_proto = {
  	.name     = "NFC_RAW",
  	.owner    = THIS_MODULE,
  	.obj_size = sizeof(struct nfc_rawsock),
  };
  
  static const struct nfc_protocol rawsock_nfc_proto = {
  	.id	  = NFC_SOCKPROTO_RAW,
  	.proto    = &rawsock_proto,
  	.owner    = THIS_MODULE,
  	.create   = rawsock_create
  };
  
  int __init rawsock_init(void)
  {
  	int rc;
  
  	rc = nfc_proto_register(&rawsock_nfc_proto);
  
  	return rc;
  }
  
  void rawsock_exit(void)
  {
  	nfc_proto_unregister(&rawsock_nfc_proto);
  }