18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2011 Instituto Nokia de Tecnologia
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Authors:
68c2ecf20Sopenharmony_ci *    Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
78c2ecf20Sopenharmony_ci *    Lauro Ramos Venancio <lauro.venancio@openbossa.org>
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <net/tcp_states.h>
138c2ecf20Sopenharmony_ci#include <linux/nfc.h>
148c2ecf20Sopenharmony_ci#include <linux/export.h>
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#include "nfc.h"
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_cistatic struct nfc_sock_list raw_sk_list = {
198c2ecf20Sopenharmony_ci	.lock = __RW_LOCK_UNLOCKED(raw_sk_list.lock)
208c2ecf20Sopenharmony_ci};
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_cistatic void nfc_sock_link(struct nfc_sock_list *l, struct sock *sk)
238c2ecf20Sopenharmony_ci{
248c2ecf20Sopenharmony_ci	write_lock(&l->lock);
258c2ecf20Sopenharmony_ci	sk_add_node(sk, &l->head);
268c2ecf20Sopenharmony_ci	write_unlock(&l->lock);
278c2ecf20Sopenharmony_ci}
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_cistatic void nfc_sock_unlink(struct nfc_sock_list *l, struct sock *sk)
308c2ecf20Sopenharmony_ci{
318c2ecf20Sopenharmony_ci	write_lock(&l->lock);
328c2ecf20Sopenharmony_ci	sk_del_node_init(sk);
338c2ecf20Sopenharmony_ci	write_unlock(&l->lock);
348c2ecf20Sopenharmony_ci}
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cistatic void rawsock_write_queue_purge(struct sock *sk)
378c2ecf20Sopenharmony_ci{
388c2ecf20Sopenharmony_ci	pr_debug("sk=%p\n", sk);
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	spin_lock_bh(&sk->sk_write_queue.lock);
418c2ecf20Sopenharmony_ci	__skb_queue_purge(&sk->sk_write_queue);
428c2ecf20Sopenharmony_ci	nfc_rawsock(sk)->tx_work_scheduled = false;
438c2ecf20Sopenharmony_ci	spin_unlock_bh(&sk->sk_write_queue.lock);
448c2ecf20Sopenharmony_ci}
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_cistatic void rawsock_report_error(struct sock *sk, int err)
478c2ecf20Sopenharmony_ci{
488c2ecf20Sopenharmony_ci	pr_debug("sk=%p err=%d\n", sk, err);
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	sk->sk_shutdown = SHUTDOWN_MASK;
518c2ecf20Sopenharmony_ci	sk->sk_err = -err;
528c2ecf20Sopenharmony_ci	sk->sk_error_report(sk);
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	rawsock_write_queue_purge(sk);
558c2ecf20Sopenharmony_ci}
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cistatic int rawsock_release(struct socket *sock)
588c2ecf20Sopenharmony_ci{
598c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	pr_debug("sock=%p sk=%p\n", sock, sk);
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	if (!sk)
648c2ecf20Sopenharmony_ci		return 0;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	if (sock->type == SOCK_RAW)
678c2ecf20Sopenharmony_ci		nfc_sock_unlink(&raw_sk_list, sk);
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	sock_orphan(sk);
708c2ecf20Sopenharmony_ci	sock_put(sk);
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	return 0;
738c2ecf20Sopenharmony_ci}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_cistatic int rawsock_connect(struct socket *sock, struct sockaddr *_addr,
768c2ecf20Sopenharmony_ci			   int len, int flags)
778c2ecf20Sopenharmony_ci{
788c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
798c2ecf20Sopenharmony_ci	struct sockaddr_nfc *addr = (struct sockaddr_nfc *)_addr;
808c2ecf20Sopenharmony_ci	struct nfc_dev *dev;
818c2ecf20Sopenharmony_ci	int rc = 0;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	pr_debug("sock=%p sk=%p flags=%d\n", sock, sk, flags);
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	if (!addr || len < sizeof(struct sockaddr_nfc) ||
868c2ecf20Sopenharmony_ci	    addr->sa_family != AF_NFC)
878c2ecf20Sopenharmony_ci		return -EINVAL;
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	pr_debug("addr dev_idx=%u target_idx=%u protocol=%u\n",
908c2ecf20Sopenharmony_ci		 addr->dev_idx, addr->target_idx, addr->nfc_protocol);
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	lock_sock(sk);
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	if (sock->state == SS_CONNECTED) {
958c2ecf20Sopenharmony_ci		rc = -EISCONN;
968c2ecf20Sopenharmony_ci		goto error;
978c2ecf20Sopenharmony_ci	}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	dev = nfc_get_device(addr->dev_idx);
1008c2ecf20Sopenharmony_ci	if (!dev) {
1018c2ecf20Sopenharmony_ci		rc = -ENODEV;
1028c2ecf20Sopenharmony_ci		goto error;
1038c2ecf20Sopenharmony_ci	}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	if (addr->target_idx > dev->target_next_idx - 1 ||
1068c2ecf20Sopenharmony_ci	    addr->target_idx < dev->target_next_idx - dev->n_targets) {
1078c2ecf20Sopenharmony_ci		rc = -EINVAL;
1088c2ecf20Sopenharmony_ci		goto put_dev;
1098c2ecf20Sopenharmony_ci	}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	rc = nfc_activate_target(dev, addr->target_idx, addr->nfc_protocol);
1128c2ecf20Sopenharmony_ci	if (rc)
1138c2ecf20Sopenharmony_ci		goto put_dev;
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	nfc_rawsock(sk)->dev = dev;
1168c2ecf20Sopenharmony_ci	nfc_rawsock(sk)->target_idx = addr->target_idx;
1178c2ecf20Sopenharmony_ci	sock->state = SS_CONNECTED;
1188c2ecf20Sopenharmony_ci	sk->sk_state = TCP_ESTABLISHED;
1198c2ecf20Sopenharmony_ci	sk->sk_state_change(sk);
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	release_sock(sk);
1228c2ecf20Sopenharmony_ci	return 0;
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ciput_dev:
1258c2ecf20Sopenharmony_ci	nfc_put_device(dev);
1268c2ecf20Sopenharmony_cierror:
1278c2ecf20Sopenharmony_ci	release_sock(sk);
1288c2ecf20Sopenharmony_ci	return rc;
1298c2ecf20Sopenharmony_ci}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_cistatic int rawsock_add_header(struct sk_buff *skb)
1328c2ecf20Sopenharmony_ci{
1338c2ecf20Sopenharmony_ci	*(u8 *)skb_push(skb, NFC_HEADER_SIZE) = 0;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	return 0;
1368c2ecf20Sopenharmony_ci}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_cistatic void rawsock_data_exchange_complete(void *context, struct sk_buff *skb,
1398c2ecf20Sopenharmony_ci					   int err)
1408c2ecf20Sopenharmony_ci{
1418c2ecf20Sopenharmony_ci	struct sock *sk = (struct sock *) context;
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	BUG_ON(in_irq());
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	pr_debug("sk=%p err=%d\n", sk, err);
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	if (err)
1488c2ecf20Sopenharmony_ci		goto error;
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	err = rawsock_add_header(skb);
1518c2ecf20Sopenharmony_ci	if (err)
1528c2ecf20Sopenharmony_ci		goto error_skb;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	err = sock_queue_rcv_skb(sk, skb);
1558c2ecf20Sopenharmony_ci	if (err)
1568c2ecf20Sopenharmony_ci		goto error_skb;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	spin_lock_bh(&sk->sk_write_queue.lock);
1598c2ecf20Sopenharmony_ci	if (!skb_queue_empty(&sk->sk_write_queue))
1608c2ecf20Sopenharmony_ci		schedule_work(&nfc_rawsock(sk)->tx_work);
1618c2ecf20Sopenharmony_ci	else
1628c2ecf20Sopenharmony_ci		nfc_rawsock(sk)->tx_work_scheduled = false;
1638c2ecf20Sopenharmony_ci	spin_unlock_bh(&sk->sk_write_queue.lock);
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	sock_put(sk);
1668c2ecf20Sopenharmony_ci	return;
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_cierror_skb:
1698c2ecf20Sopenharmony_ci	kfree_skb(skb);
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_cierror:
1728c2ecf20Sopenharmony_ci	rawsock_report_error(sk, err);
1738c2ecf20Sopenharmony_ci	sock_put(sk);
1748c2ecf20Sopenharmony_ci}
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_cistatic void rawsock_tx_work(struct work_struct *work)
1778c2ecf20Sopenharmony_ci{
1788c2ecf20Sopenharmony_ci	struct sock *sk = to_rawsock_sk(work);
1798c2ecf20Sopenharmony_ci	struct nfc_dev *dev = nfc_rawsock(sk)->dev;
1808c2ecf20Sopenharmony_ci	u32 target_idx = nfc_rawsock(sk)->target_idx;
1818c2ecf20Sopenharmony_ci	struct sk_buff *skb;
1828c2ecf20Sopenharmony_ci	int rc;
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	pr_debug("sk=%p target_idx=%u\n", sk, target_idx);
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	if (sk->sk_shutdown & SEND_SHUTDOWN) {
1878c2ecf20Sopenharmony_ci		rawsock_write_queue_purge(sk);
1888c2ecf20Sopenharmony_ci		return;
1898c2ecf20Sopenharmony_ci	}
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	skb = skb_dequeue(&sk->sk_write_queue);
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	sock_hold(sk);
1948c2ecf20Sopenharmony_ci	rc = nfc_data_exchange(dev, target_idx, skb,
1958c2ecf20Sopenharmony_ci			       rawsock_data_exchange_complete, sk);
1968c2ecf20Sopenharmony_ci	if (rc) {
1978c2ecf20Sopenharmony_ci		rawsock_report_error(sk, rc);
1988c2ecf20Sopenharmony_ci		sock_put(sk);
1998c2ecf20Sopenharmony_ci	}
2008c2ecf20Sopenharmony_ci}
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_cistatic int rawsock_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
2038c2ecf20Sopenharmony_ci{
2048c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
2058c2ecf20Sopenharmony_ci	struct nfc_dev *dev = nfc_rawsock(sk)->dev;
2068c2ecf20Sopenharmony_ci	struct sk_buff *skb;
2078c2ecf20Sopenharmony_ci	int rc;
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	pr_debug("sock=%p sk=%p len=%zu\n", sock, sk, len);
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	if (msg->msg_namelen)
2128c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	if (sock->state != SS_CONNECTED)
2158c2ecf20Sopenharmony_ci		return -ENOTCONN;
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	skb = nfc_alloc_send_skb(dev, sk, msg->msg_flags, len, &rc);
2188c2ecf20Sopenharmony_ci	if (skb == NULL)
2198c2ecf20Sopenharmony_ci		return rc;
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	rc = memcpy_from_msg(skb_put(skb, len), msg, len);
2228c2ecf20Sopenharmony_ci	if (rc < 0) {
2238c2ecf20Sopenharmony_ci		kfree_skb(skb);
2248c2ecf20Sopenharmony_ci		return rc;
2258c2ecf20Sopenharmony_ci	}
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	spin_lock_bh(&sk->sk_write_queue.lock);
2288c2ecf20Sopenharmony_ci	__skb_queue_tail(&sk->sk_write_queue, skb);
2298c2ecf20Sopenharmony_ci	if (!nfc_rawsock(sk)->tx_work_scheduled) {
2308c2ecf20Sopenharmony_ci		schedule_work(&nfc_rawsock(sk)->tx_work);
2318c2ecf20Sopenharmony_ci		nfc_rawsock(sk)->tx_work_scheduled = true;
2328c2ecf20Sopenharmony_ci	}
2338c2ecf20Sopenharmony_ci	spin_unlock_bh(&sk->sk_write_queue.lock);
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	return len;
2368c2ecf20Sopenharmony_ci}
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_cistatic int rawsock_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
2398c2ecf20Sopenharmony_ci			   int flags)
2408c2ecf20Sopenharmony_ci{
2418c2ecf20Sopenharmony_ci	int noblock = flags & MSG_DONTWAIT;
2428c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
2438c2ecf20Sopenharmony_ci	struct sk_buff *skb;
2448c2ecf20Sopenharmony_ci	int copied;
2458c2ecf20Sopenharmony_ci	int rc;
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	pr_debug("sock=%p sk=%p len=%zu flags=%d\n", sock, sk, len, flags);
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	skb = skb_recv_datagram(sk, flags, noblock, &rc);
2508c2ecf20Sopenharmony_ci	if (!skb)
2518c2ecf20Sopenharmony_ci		return rc;
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	copied = skb->len;
2548c2ecf20Sopenharmony_ci	if (len < copied) {
2558c2ecf20Sopenharmony_ci		msg->msg_flags |= MSG_TRUNC;
2568c2ecf20Sopenharmony_ci		copied = len;
2578c2ecf20Sopenharmony_ci	}
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	rc = skb_copy_datagram_msg(skb, 0, msg, copied);
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	skb_free_datagram(sk, skb);
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	return rc ? : copied;
2648c2ecf20Sopenharmony_ci}
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_cistatic const struct proto_ops rawsock_ops = {
2678c2ecf20Sopenharmony_ci	.family         = PF_NFC,
2688c2ecf20Sopenharmony_ci	.owner          = THIS_MODULE,
2698c2ecf20Sopenharmony_ci	.release        = rawsock_release,
2708c2ecf20Sopenharmony_ci	.bind           = sock_no_bind,
2718c2ecf20Sopenharmony_ci	.connect        = rawsock_connect,
2728c2ecf20Sopenharmony_ci	.socketpair     = sock_no_socketpair,
2738c2ecf20Sopenharmony_ci	.accept         = sock_no_accept,
2748c2ecf20Sopenharmony_ci	.getname        = sock_no_getname,
2758c2ecf20Sopenharmony_ci	.poll           = datagram_poll,
2768c2ecf20Sopenharmony_ci	.ioctl          = sock_no_ioctl,
2778c2ecf20Sopenharmony_ci	.listen         = sock_no_listen,
2788c2ecf20Sopenharmony_ci	.shutdown       = sock_no_shutdown,
2798c2ecf20Sopenharmony_ci	.sendmsg        = rawsock_sendmsg,
2808c2ecf20Sopenharmony_ci	.recvmsg        = rawsock_recvmsg,
2818c2ecf20Sopenharmony_ci	.mmap           = sock_no_mmap,
2828c2ecf20Sopenharmony_ci};
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_cistatic const struct proto_ops rawsock_raw_ops = {
2858c2ecf20Sopenharmony_ci	.family         = PF_NFC,
2868c2ecf20Sopenharmony_ci	.owner          = THIS_MODULE,
2878c2ecf20Sopenharmony_ci	.release        = rawsock_release,
2888c2ecf20Sopenharmony_ci	.bind           = sock_no_bind,
2898c2ecf20Sopenharmony_ci	.connect        = sock_no_connect,
2908c2ecf20Sopenharmony_ci	.socketpair     = sock_no_socketpair,
2918c2ecf20Sopenharmony_ci	.accept         = sock_no_accept,
2928c2ecf20Sopenharmony_ci	.getname        = sock_no_getname,
2938c2ecf20Sopenharmony_ci	.poll           = datagram_poll,
2948c2ecf20Sopenharmony_ci	.ioctl          = sock_no_ioctl,
2958c2ecf20Sopenharmony_ci	.listen         = sock_no_listen,
2968c2ecf20Sopenharmony_ci	.shutdown       = sock_no_shutdown,
2978c2ecf20Sopenharmony_ci	.sendmsg        = sock_no_sendmsg,
2988c2ecf20Sopenharmony_ci	.recvmsg        = rawsock_recvmsg,
2998c2ecf20Sopenharmony_ci	.mmap           = sock_no_mmap,
3008c2ecf20Sopenharmony_ci};
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_cistatic void rawsock_destruct(struct sock *sk)
3038c2ecf20Sopenharmony_ci{
3048c2ecf20Sopenharmony_ci	pr_debug("sk=%p\n", sk);
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	if (sk->sk_state == TCP_ESTABLISHED) {
3078c2ecf20Sopenharmony_ci		nfc_deactivate_target(nfc_rawsock(sk)->dev,
3088c2ecf20Sopenharmony_ci				      nfc_rawsock(sk)->target_idx,
3098c2ecf20Sopenharmony_ci				      NFC_TARGET_MODE_IDLE);
3108c2ecf20Sopenharmony_ci		nfc_put_device(nfc_rawsock(sk)->dev);
3118c2ecf20Sopenharmony_ci	}
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	skb_queue_purge(&sk->sk_receive_queue);
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	if (!sock_flag(sk, SOCK_DEAD)) {
3168c2ecf20Sopenharmony_ci		pr_err("Freeing alive NFC raw socket %p\n", sk);
3178c2ecf20Sopenharmony_ci		return;
3188c2ecf20Sopenharmony_ci	}
3198c2ecf20Sopenharmony_ci}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_cistatic int rawsock_create(struct net *net, struct socket *sock,
3228c2ecf20Sopenharmony_ci			  const struct nfc_protocol *nfc_proto, int kern)
3238c2ecf20Sopenharmony_ci{
3248c2ecf20Sopenharmony_ci	struct sock *sk;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	pr_debug("sock=%p\n", sock);
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	if ((sock->type != SOCK_SEQPACKET) && (sock->type != SOCK_RAW))
3298c2ecf20Sopenharmony_ci		return -ESOCKTNOSUPPORT;
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	if (sock->type == SOCK_RAW) {
3328c2ecf20Sopenharmony_ci		if (!ns_capable(net->user_ns, CAP_NET_RAW))
3338c2ecf20Sopenharmony_ci			return -EPERM;
3348c2ecf20Sopenharmony_ci		sock->ops = &rawsock_raw_ops;
3358c2ecf20Sopenharmony_ci	} else {
3368c2ecf20Sopenharmony_ci		sock->ops = &rawsock_ops;
3378c2ecf20Sopenharmony_ci	}
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	sk = sk_alloc(net, PF_NFC, GFP_ATOMIC, nfc_proto->proto, kern);
3408c2ecf20Sopenharmony_ci	if (!sk)
3418c2ecf20Sopenharmony_ci		return -ENOMEM;
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	sock_init_data(sock, sk);
3448c2ecf20Sopenharmony_ci	sk->sk_protocol = nfc_proto->id;
3458c2ecf20Sopenharmony_ci	sk->sk_destruct = rawsock_destruct;
3468c2ecf20Sopenharmony_ci	sock->state = SS_UNCONNECTED;
3478c2ecf20Sopenharmony_ci	if (sock->type == SOCK_RAW)
3488c2ecf20Sopenharmony_ci		nfc_sock_link(&raw_sk_list, sk);
3498c2ecf20Sopenharmony_ci	else {
3508c2ecf20Sopenharmony_ci		INIT_WORK(&nfc_rawsock(sk)->tx_work, rawsock_tx_work);
3518c2ecf20Sopenharmony_ci		nfc_rawsock(sk)->tx_work_scheduled = false;
3528c2ecf20Sopenharmony_ci	}
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	return 0;
3558c2ecf20Sopenharmony_ci}
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_civoid nfc_send_to_raw_sock(struct nfc_dev *dev, struct sk_buff *skb,
3588c2ecf20Sopenharmony_ci			  u8 payload_type, u8 direction)
3598c2ecf20Sopenharmony_ci{
3608c2ecf20Sopenharmony_ci	struct sk_buff *skb_copy = NULL, *nskb;
3618c2ecf20Sopenharmony_ci	struct sock *sk;
3628c2ecf20Sopenharmony_ci	u8 *data;
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	read_lock(&raw_sk_list.lock);
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	sk_for_each(sk, &raw_sk_list.head) {
3678c2ecf20Sopenharmony_ci		if (!skb_copy) {
3688c2ecf20Sopenharmony_ci			skb_copy = __pskb_copy_fclone(skb, NFC_RAW_HEADER_SIZE,
3698c2ecf20Sopenharmony_ci						      GFP_ATOMIC, true);
3708c2ecf20Sopenharmony_ci			if (!skb_copy)
3718c2ecf20Sopenharmony_ci				continue;
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci			data = skb_push(skb_copy, NFC_RAW_HEADER_SIZE);
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci			data[0] = dev ? dev->idx : 0xFF;
3768c2ecf20Sopenharmony_ci			data[1] = direction & 0x01;
3778c2ecf20Sopenharmony_ci			data[1] |= (payload_type << 1);
3788c2ecf20Sopenharmony_ci		}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci		nskb = skb_clone(skb_copy, GFP_ATOMIC);
3818c2ecf20Sopenharmony_ci		if (!nskb)
3828c2ecf20Sopenharmony_ci			continue;
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci		if (sock_queue_rcv_skb(sk, nskb))
3858c2ecf20Sopenharmony_ci			kfree_skb(nskb);
3868c2ecf20Sopenharmony_ci	}
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	read_unlock(&raw_sk_list.lock);
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	kfree_skb(skb_copy);
3918c2ecf20Sopenharmony_ci}
3928c2ecf20Sopenharmony_ciEXPORT_SYMBOL(nfc_send_to_raw_sock);
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_cistatic struct proto rawsock_proto = {
3958c2ecf20Sopenharmony_ci	.name     = "NFC_RAW",
3968c2ecf20Sopenharmony_ci	.owner    = THIS_MODULE,
3978c2ecf20Sopenharmony_ci	.obj_size = sizeof(struct nfc_rawsock),
3988c2ecf20Sopenharmony_ci};
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_cistatic const struct nfc_protocol rawsock_nfc_proto = {
4018c2ecf20Sopenharmony_ci	.id	  = NFC_SOCKPROTO_RAW,
4028c2ecf20Sopenharmony_ci	.proto    = &rawsock_proto,
4038c2ecf20Sopenharmony_ci	.owner    = THIS_MODULE,
4048c2ecf20Sopenharmony_ci	.create   = rawsock_create
4058c2ecf20Sopenharmony_ci};
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ciint __init rawsock_init(void)
4088c2ecf20Sopenharmony_ci{
4098c2ecf20Sopenharmony_ci	int rc;
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	rc = nfc_proto_register(&rawsock_nfc_proto);
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	return rc;
4148c2ecf20Sopenharmony_ci}
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_civoid rawsock_exit(void)
4178c2ecf20Sopenharmony_ci{
4188c2ecf20Sopenharmony_ci	nfc_proto_unregister(&rawsock_nfc_proto);
4198c2ecf20Sopenharmony_ci}
420