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