162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2011 Instituto Nokia de Tecnologia 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Authors: 662306a36Sopenharmony_ci * Aloisio Almeida Jr <aloisio.almeida@openbossa.org> 762306a36Sopenharmony_ci * Lauro Ramos Venancio <lauro.venancio@openbossa.org> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <net/tcp_states.h> 1362306a36Sopenharmony_ci#include <linux/nfc.h> 1462306a36Sopenharmony_ci#include <linux/export.h> 1562306a36Sopenharmony_ci#include <linux/kcov.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include "nfc.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistatic struct nfc_sock_list raw_sk_list = { 2062306a36Sopenharmony_ci .lock = __RW_LOCK_UNLOCKED(raw_sk_list.lock) 2162306a36Sopenharmony_ci}; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic void nfc_sock_link(struct nfc_sock_list *l, struct sock *sk) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci write_lock(&l->lock); 2662306a36Sopenharmony_ci sk_add_node(sk, &l->head); 2762306a36Sopenharmony_ci write_unlock(&l->lock); 2862306a36Sopenharmony_ci} 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistatic void nfc_sock_unlink(struct nfc_sock_list *l, struct sock *sk) 3162306a36Sopenharmony_ci{ 3262306a36Sopenharmony_ci write_lock(&l->lock); 3362306a36Sopenharmony_ci sk_del_node_init(sk); 3462306a36Sopenharmony_ci write_unlock(&l->lock); 3562306a36Sopenharmony_ci} 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistatic void rawsock_write_queue_purge(struct sock *sk) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci pr_debug("sk=%p\n", sk); 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci spin_lock_bh(&sk->sk_write_queue.lock); 4262306a36Sopenharmony_ci __skb_queue_purge(&sk->sk_write_queue); 4362306a36Sopenharmony_ci nfc_rawsock(sk)->tx_work_scheduled = false; 4462306a36Sopenharmony_ci spin_unlock_bh(&sk->sk_write_queue.lock); 4562306a36Sopenharmony_ci} 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic void rawsock_report_error(struct sock *sk, int err) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci pr_debug("sk=%p err=%d\n", sk, err); 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci sk->sk_shutdown = SHUTDOWN_MASK; 5262306a36Sopenharmony_ci sk->sk_err = -err; 5362306a36Sopenharmony_ci sk_error_report(sk); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci rawsock_write_queue_purge(sk); 5662306a36Sopenharmony_ci} 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cistatic int rawsock_release(struct socket *sock) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci struct sock *sk = sock->sk; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci pr_debug("sock=%p sk=%p\n", sock, sk); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci if (!sk) 6562306a36Sopenharmony_ci return 0; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci if (sock->type == SOCK_RAW) 6862306a36Sopenharmony_ci nfc_sock_unlink(&raw_sk_list, sk); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci sock_orphan(sk); 7162306a36Sopenharmony_ci sock_put(sk); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci return 0; 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistatic int rawsock_connect(struct socket *sock, struct sockaddr *_addr, 7762306a36Sopenharmony_ci int len, int flags) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci struct sock *sk = sock->sk; 8062306a36Sopenharmony_ci struct sockaddr_nfc *addr = (struct sockaddr_nfc *)_addr; 8162306a36Sopenharmony_ci struct nfc_dev *dev; 8262306a36Sopenharmony_ci int rc = 0; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci pr_debug("sock=%p sk=%p flags=%d\n", sock, sk, flags); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci if (!addr || len < sizeof(struct sockaddr_nfc) || 8762306a36Sopenharmony_ci addr->sa_family != AF_NFC) 8862306a36Sopenharmony_ci return -EINVAL; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci pr_debug("addr dev_idx=%u target_idx=%u protocol=%u\n", 9162306a36Sopenharmony_ci addr->dev_idx, addr->target_idx, addr->nfc_protocol); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci lock_sock(sk); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci if (sock->state == SS_CONNECTED) { 9662306a36Sopenharmony_ci rc = -EISCONN; 9762306a36Sopenharmony_ci goto error; 9862306a36Sopenharmony_ci } 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci dev = nfc_get_device(addr->dev_idx); 10162306a36Sopenharmony_ci if (!dev) { 10262306a36Sopenharmony_ci rc = -ENODEV; 10362306a36Sopenharmony_ci goto error; 10462306a36Sopenharmony_ci } 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci if (addr->target_idx > dev->target_next_idx - 1 || 10762306a36Sopenharmony_ci addr->target_idx < dev->target_next_idx - dev->n_targets) { 10862306a36Sopenharmony_ci rc = -EINVAL; 10962306a36Sopenharmony_ci goto put_dev; 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci rc = nfc_activate_target(dev, addr->target_idx, addr->nfc_protocol); 11362306a36Sopenharmony_ci if (rc) 11462306a36Sopenharmony_ci goto put_dev; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci nfc_rawsock(sk)->dev = dev; 11762306a36Sopenharmony_ci nfc_rawsock(sk)->target_idx = addr->target_idx; 11862306a36Sopenharmony_ci sock->state = SS_CONNECTED; 11962306a36Sopenharmony_ci sk->sk_state = TCP_ESTABLISHED; 12062306a36Sopenharmony_ci sk->sk_state_change(sk); 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci release_sock(sk); 12362306a36Sopenharmony_ci return 0; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ciput_dev: 12662306a36Sopenharmony_ci nfc_put_device(dev); 12762306a36Sopenharmony_cierror: 12862306a36Sopenharmony_ci release_sock(sk); 12962306a36Sopenharmony_ci return rc; 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cistatic int rawsock_add_header(struct sk_buff *skb) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci *(u8 *)skb_push(skb, NFC_HEADER_SIZE) = 0; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci return 0; 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_cistatic void rawsock_data_exchange_complete(void *context, struct sk_buff *skb, 14062306a36Sopenharmony_ci int err) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci struct sock *sk = (struct sock *) context; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci BUG_ON(in_hardirq()); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci pr_debug("sk=%p err=%d\n", sk, err); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci if (err) 14962306a36Sopenharmony_ci goto error; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci err = rawsock_add_header(skb); 15262306a36Sopenharmony_ci if (err) 15362306a36Sopenharmony_ci goto error_skb; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci err = sock_queue_rcv_skb(sk, skb); 15662306a36Sopenharmony_ci if (err) 15762306a36Sopenharmony_ci goto error_skb; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci spin_lock_bh(&sk->sk_write_queue.lock); 16062306a36Sopenharmony_ci if (!skb_queue_empty(&sk->sk_write_queue)) 16162306a36Sopenharmony_ci schedule_work(&nfc_rawsock(sk)->tx_work); 16262306a36Sopenharmony_ci else 16362306a36Sopenharmony_ci nfc_rawsock(sk)->tx_work_scheduled = false; 16462306a36Sopenharmony_ci spin_unlock_bh(&sk->sk_write_queue.lock); 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci sock_put(sk); 16762306a36Sopenharmony_ci return; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cierror_skb: 17062306a36Sopenharmony_ci kfree_skb(skb); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cierror: 17362306a36Sopenharmony_ci rawsock_report_error(sk, err); 17462306a36Sopenharmony_ci sock_put(sk); 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_cistatic void rawsock_tx_work(struct work_struct *work) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci struct sock *sk = to_rawsock_sk(work); 18062306a36Sopenharmony_ci struct nfc_dev *dev = nfc_rawsock(sk)->dev; 18162306a36Sopenharmony_ci u32 target_idx = nfc_rawsock(sk)->target_idx; 18262306a36Sopenharmony_ci struct sk_buff *skb; 18362306a36Sopenharmony_ci int rc; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci pr_debug("sk=%p target_idx=%u\n", sk, target_idx); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci if (sk->sk_shutdown & SEND_SHUTDOWN) { 18862306a36Sopenharmony_ci rawsock_write_queue_purge(sk); 18962306a36Sopenharmony_ci return; 19062306a36Sopenharmony_ci } 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci skb = skb_dequeue(&sk->sk_write_queue); 19362306a36Sopenharmony_ci kcov_remote_start_common(skb_get_kcov_handle(skb)); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci sock_hold(sk); 19662306a36Sopenharmony_ci rc = nfc_data_exchange(dev, target_idx, skb, 19762306a36Sopenharmony_ci rawsock_data_exchange_complete, sk); 19862306a36Sopenharmony_ci if (rc) { 19962306a36Sopenharmony_ci rawsock_report_error(sk, rc); 20062306a36Sopenharmony_ci sock_put(sk); 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci kcov_remote_stop(); 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_cistatic int rawsock_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) 20662306a36Sopenharmony_ci{ 20762306a36Sopenharmony_ci struct sock *sk = sock->sk; 20862306a36Sopenharmony_ci struct nfc_dev *dev = nfc_rawsock(sk)->dev; 20962306a36Sopenharmony_ci struct sk_buff *skb; 21062306a36Sopenharmony_ci int rc; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci pr_debug("sock=%p sk=%p len=%zu\n", sock, sk, len); 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci if (msg->msg_namelen) 21562306a36Sopenharmony_ci return -EOPNOTSUPP; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci if (sock->state != SS_CONNECTED) 21862306a36Sopenharmony_ci return -ENOTCONN; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci skb = nfc_alloc_send_skb(dev, sk, msg->msg_flags, len, &rc); 22162306a36Sopenharmony_ci if (skb == NULL) 22262306a36Sopenharmony_ci return rc; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci rc = memcpy_from_msg(skb_put(skb, len), msg, len); 22562306a36Sopenharmony_ci if (rc < 0) { 22662306a36Sopenharmony_ci kfree_skb(skb); 22762306a36Sopenharmony_ci return rc; 22862306a36Sopenharmony_ci } 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci spin_lock_bh(&sk->sk_write_queue.lock); 23162306a36Sopenharmony_ci __skb_queue_tail(&sk->sk_write_queue, skb); 23262306a36Sopenharmony_ci if (!nfc_rawsock(sk)->tx_work_scheduled) { 23362306a36Sopenharmony_ci schedule_work(&nfc_rawsock(sk)->tx_work); 23462306a36Sopenharmony_ci nfc_rawsock(sk)->tx_work_scheduled = true; 23562306a36Sopenharmony_ci } 23662306a36Sopenharmony_ci spin_unlock_bh(&sk->sk_write_queue.lock); 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci return len; 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_cistatic int rawsock_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, 24262306a36Sopenharmony_ci int flags) 24362306a36Sopenharmony_ci{ 24462306a36Sopenharmony_ci struct sock *sk = sock->sk; 24562306a36Sopenharmony_ci struct sk_buff *skb; 24662306a36Sopenharmony_ci int copied; 24762306a36Sopenharmony_ci int rc; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci pr_debug("sock=%p sk=%p len=%zu flags=%d\n", sock, sk, len, flags); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci skb = skb_recv_datagram(sk, flags, &rc); 25262306a36Sopenharmony_ci if (!skb) 25362306a36Sopenharmony_ci return rc; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci copied = skb->len; 25662306a36Sopenharmony_ci if (len < copied) { 25762306a36Sopenharmony_ci msg->msg_flags |= MSG_TRUNC; 25862306a36Sopenharmony_ci copied = len; 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci rc = skb_copy_datagram_msg(skb, 0, msg, copied); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci skb_free_datagram(sk, skb); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci return rc ? : copied; 26662306a36Sopenharmony_ci} 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_cistatic const struct proto_ops rawsock_ops = { 26962306a36Sopenharmony_ci .family = PF_NFC, 27062306a36Sopenharmony_ci .owner = THIS_MODULE, 27162306a36Sopenharmony_ci .release = rawsock_release, 27262306a36Sopenharmony_ci .bind = sock_no_bind, 27362306a36Sopenharmony_ci .connect = rawsock_connect, 27462306a36Sopenharmony_ci .socketpair = sock_no_socketpair, 27562306a36Sopenharmony_ci .accept = sock_no_accept, 27662306a36Sopenharmony_ci .getname = sock_no_getname, 27762306a36Sopenharmony_ci .poll = datagram_poll, 27862306a36Sopenharmony_ci .ioctl = sock_no_ioctl, 27962306a36Sopenharmony_ci .listen = sock_no_listen, 28062306a36Sopenharmony_ci .shutdown = sock_no_shutdown, 28162306a36Sopenharmony_ci .sendmsg = rawsock_sendmsg, 28262306a36Sopenharmony_ci .recvmsg = rawsock_recvmsg, 28362306a36Sopenharmony_ci .mmap = sock_no_mmap, 28462306a36Sopenharmony_ci}; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cistatic const struct proto_ops rawsock_raw_ops = { 28762306a36Sopenharmony_ci .family = PF_NFC, 28862306a36Sopenharmony_ci .owner = THIS_MODULE, 28962306a36Sopenharmony_ci .release = rawsock_release, 29062306a36Sopenharmony_ci .bind = sock_no_bind, 29162306a36Sopenharmony_ci .connect = sock_no_connect, 29262306a36Sopenharmony_ci .socketpair = sock_no_socketpair, 29362306a36Sopenharmony_ci .accept = sock_no_accept, 29462306a36Sopenharmony_ci .getname = sock_no_getname, 29562306a36Sopenharmony_ci .poll = datagram_poll, 29662306a36Sopenharmony_ci .ioctl = sock_no_ioctl, 29762306a36Sopenharmony_ci .listen = sock_no_listen, 29862306a36Sopenharmony_ci .shutdown = sock_no_shutdown, 29962306a36Sopenharmony_ci .sendmsg = sock_no_sendmsg, 30062306a36Sopenharmony_ci .recvmsg = rawsock_recvmsg, 30162306a36Sopenharmony_ci .mmap = sock_no_mmap, 30262306a36Sopenharmony_ci}; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_cistatic void rawsock_destruct(struct sock *sk) 30562306a36Sopenharmony_ci{ 30662306a36Sopenharmony_ci pr_debug("sk=%p\n", sk); 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci if (sk->sk_state == TCP_ESTABLISHED) { 30962306a36Sopenharmony_ci nfc_deactivate_target(nfc_rawsock(sk)->dev, 31062306a36Sopenharmony_ci nfc_rawsock(sk)->target_idx, 31162306a36Sopenharmony_ci NFC_TARGET_MODE_IDLE); 31262306a36Sopenharmony_ci nfc_put_device(nfc_rawsock(sk)->dev); 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci skb_queue_purge(&sk->sk_receive_queue); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci if (!sock_flag(sk, SOCK_DEAD)) { 31862306a36Sopenharmony_ci pr_err("Freeing alive NFC raw socket %p\n", sk); 31962306a36Sopenharmony_ci return; 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_cistatic int rawsock_create(struct net *net, struct socket *sock, 32462306a36Sopenharmony_ci const struct nfc_protocol *nfc_proto, int kern) 32562306a36Sopenharmony_ci{ 32662306a36Sopenharmony_ci struct sock *sk; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci pr_debug("sock=%p\n", sock); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci if ((sock->type != SOCK_SEQPACKET) && (sock->type != SOCK_RAW)) 33162306a36Sopenharmony_ci return -ESOCKTNOSUPPORT; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci if (sock->type == SOCK_RAW) { 33462306a36Sopenharmony_ci if (!ns_capable(net->user_ns, CAP_NET_RAW)) 33562306a36Sopenharmony_ci return -EPERM; 33662306a36Sopenharmony_ci sock->ops = &rawsock_raw_ops; 33762306a36Sopenharmony_ci } else { 33862306a36Sopenharmony_ci sock->ops = &rawsock_ops; 33962306a36Sopenharmony_ci } 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci sk = sk_alloc(net, PF_NFC, GFP_ATOMIC, nfc_proto->proto, kern); 34262306a36Sopenharmony_ci if (!sk) 34362306a36Sopenharmony_ci return -ENOMEM; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci sock_init_data(sock, sk); 34662306a36Sopenharmony_ci sk->sk_protocol = nfc_proto->id; 34762306a36Sopenharmony_ci sk->sk_destruct = rawsock_destruct; 34862306a36Sopenharmony_ci sock->state = SS_UNCONNECTED; 34962306a36Sopenharmony_ci if (sock->type == SOCK_RAW) 35062306a36Sopenharmony_ci nfc_sock_link(&raw_sk_list, sk); 35162306a36Sopenharmony_ci else { 35262306a36Sopenharmony_ci INIT_WORK(&nfc_rawsock(sk)->tx_work, rawsock_tx_work); 35362306a36Sopenharmony_ci nfc_rawsock(sk)->tx_work_scheduled = false; 35462306a36Sopenharmony_ci } 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci return 0; 35762306a36Sopenharmony_ci} 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_civoid nfc_send_to_raw_sock(struct nfc_dev *dev, struct sk_buff *skb, 36062306a36Sopenharmony_ci u8 payload_type, u8 direction) 36162306a36Sopenharmony_ci{ 36262306a36Sopenharmony_ci struct sk_buff *skb_copy = NULL, *nskb; 36362306a36Sopenharmony_ci struct sock *sk; 36462306a36Sopenharmony_ci u8 *data; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci read_lock(&raw_sk_list.lock); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci sk_for_each(sk, &raw_sk_list.head) { 36962306a36Sopenharmony_ci if (!skb_copy) { 37062306a36Sopenharmony_ci skb_copy = __pskb_copy_fclone(skb, NFC_RAW_HEADER_SIZE, 37162306a36Sopenharmony_ci GFP_ATOMIC, true); 37262306a36Sopenharmony_ci if (!skb_copy) 37362306a36Sopenharmony_ci continue; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci data = skb_push(skb_copy, NFC_RAW_HEADER_SIZE); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci data[0] = dev ? dev->idx : 0xFF; 37862306a36Sopenharmony_ci data[1] = direction & 0x01; 37962306a36Sopenharmony_ci data[1] |= (payload_type << 1); 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci nskb = skb_clone(skb_copy, GFP_ATOMIC); 38362306a36Sopenharmony_ci if (!nskb) 38462306a36Sopenharmony_ci continue; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci if (sock_queue_rcv_skb(sk, nskb)) 38762306a36Sopenharmony_ci kfree_skb(nskb); 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci read_unlock(&raw_sk_list.lock); 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci kfree_skb(skb_copy); 39362306a36Sopenharmony_ci} 39462306a36Sopenharmony_ciEXPORT_SYMBOL(nfc_send_to_raw_sock); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_cistatic struct proto rawsock_proto = { 39762306a36Sopenharmony_ci .name = "NFC_RAW", 39862306a36Sopenharmony_ci .owner = THIS_MODULE, 39962306a36Sopenharmony_ci .obj_size = sizeof(struct nfc_rawsock), 40062306a36Sopenharmony_ci}; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_cistatic const struct nfc_protocol rawsock_nfc_proto = { 40362306a36Sopenharmony_ci .id = NFC_SOCKPROTO_RAW, 40462306a36Sopenharmony_ci .proto = &rawsock_proto, 40562306a36Sopenharmony_ci .owner = THIS_MODULE, 40662306a36Sopenharmony_ci .create = rawsock_create 40762306a36Sopenharmony_ci}; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ciint __init rawsock_init(void) 41062306a36Sopenharmony_ci{ 41162306a36Sopenharmony_ci int rc; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci rc = nfc_proto_register(&rawsock_nfc_proto); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci return rc; 41662306a36Sopenharmony_ci} 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_civoid rawsock_exit(void) 41962306a36Sopenharmony_ci{ 42062306a36Sopenharmony_ci nfc_proto_unregister(&rawsock_nfc_proto); 42162306a36Sopenharmony_ci} 422