diff options
-rw-r--r-- | drivers/nfc/pn533.c | 15 | ||||
-rw-r--r-- | include/linux/nfc.h | 11 | ||||
-rw-r--r-- | net/nfc/llcp/commands.c | 2 | ||||
-rw-r--r-- | net/nfc/llcp/llcp.c | 60 | ||||
-rw-r--r-- | net/nfc/llcp/llcp.h | 3 | ||||
-rw-r--r-- | net/nfc/llcp/sock.c | 90 | ||||
-rw-r--r-- | net/nfc/netlink.c | 46 |
7 files changed, 202 insertions, 25 deletions
diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index d123444404c8..97c440a8cd61 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c | |||
@@ -716,7 +716,7 @@ static int pn533_send_cmd_frame_async(struct pn533 *dev, | |||
716 | void *arg, gfp_t flags) | 716 | void *arg, gfp_t flags) |
717 | { | 717 | { |
718 | struct pn533_cmd *cmd; | 718 | struct pn533_cmd *cmd; |
719 | int rc; | 719 | int rc = 0; |
720 | 720 | ||
721 | nfc_dev_dbg(&dev->interface->dev, "%s", __func__); | 721 | nfc_dev_dbg(&dev->interface->dev, "%s", __func__); |
722 | 722 | ||
@@ -729,16 +729,16 @@ static int pn533_send_cmd_frame_async(struct pn533 *dev, | |||
729 | if (!rc) | 729 | if (!rc) |
730 | dev->cmd_pending = 1; | 730 | dev->cmd_pending = 1; |
731 | 731 | ||
732 | mutex_unlock(&dev->cmd_lock); | 732 | goto unlock; |
733 | |||
734 | return rc; | ||
735 | } | 733 | } |
736 | 734 | ||
737 | nfc_dev_dbg(&dev->interface->dev, "%s Queueing command", __func__); | 735 | nfc_dev_dbg(&dev->interface->dev, "%s Queueing command", __func__); |
738 | 736 | ||
739 | cmd = kzalloc(sizeof(struct pn533_cmd), flags); | 737 | cmd = kzalloc(sizeof(struct pn533_cmd), flags); |
740 | if (!cmd) | 738 | if (!cmd) { |
741 | return -ENOMEM; | 739 | rc = -ENOMEM; |
740 | goto unlock; | ||
741 | } | ||
742 | 742 | ||
743 | INIT_LIST_HEAD(&cmd->queue); | 743 | INIT_LIST_HEAD(&cmd->queue); |
744 | cmd->out_frame = out_frame; | 744 | cmd->out_frame = out_frame; |
@@ -750,9 +750,10 @@ static int pn533_send_cmd_frame_async(struct pn533 *dev, | |||
750 | 750 | ||
751 | list_add_tail(&cmd->queue, &dev->cmd_queue); | 751 | list_add_tail(&cmd->queue, &dev->cmd_queue); |
752 | 752 | ||
753 | unlock: | ||
753 | mutex_unlock(&dev->cmd_lock); | 754 | mutex_unlock(&dev->cmd_lock); |
754 | 755 | ||
755 | return 0; | 756 | return rc; |
756 | } | 757 | } |
757 | 758 | ||
758 | struct pn533_sync_cmd_response { | 759 | struct pn533_sync_cmd_response { |
diff --git a/include/linux/nfc.h b/include/linux/nfc.h index 6189f27e305b..d908d17da56d 100644 --- a/include/linux/nfc.h +++ b/include/linux/nfc.h | |||
@@ -183,4 +183,15 @@ struct sockaddr_nfc_llcp { | |||
183 | 183 | ||
184 | #define NFC_HEADER_SIZE 1 | 184 | #define NFC_HEADER_SIZE 1 |
185 | 185 | ||
186 | /** | ||
187 | * Pseudo-header info for raw socket packets | ||
188 | * First byte is the adapter index | ||
189 | * Second byte contains flags | ||
190 | * - 0x01 - Direction (0=RX, 1=TX) | ||
191 | * - 0x02-0x80 - Reserved | ||
192 | **/ | ||
193 | #define NFC_LLCP_RAW_HEADER_SIZE 2 | ||
194 | #define NFC_LLCP_DIRECTION_RX 0x00 | ||
195 | #define NFC_LLCP_DIRECTION_TX 0x01 | ||
196 | |||
186 | #endif /*__LINUX_NFC_H */ | 197 | #endif /*__LINUX_NFC_H */ |
diff --git a/net/nfc/llcp/commands.c b/net/nfc/llcp/commands.c index b982b5b890d7..c45ccd6c094c 100644 --- a/net/nfc/llcp/commands.c +++ b/net/nfc/llcp/commands.c | |||
@@ -312,6 +312,8 @@ int nfc_llcp_send_symm(struct nfc_dev *dev) | |||
312 | 312 | ||
313 | skb = llcp_add_header(skb, 0, 0, LLCP_PDU_SYMM); | 313 | skb = llcp_add_header(skb, 0, 0, LLCP_PDU_SYMM); |
314 | 314 | ||
315 | nfc_llcp_send_to_raw_sock(local, skb, NFC_LLCP_DIRECTION_TX); | ||
316 | |||
315 | return nfc_data_exchange(dev, local->target_idx, skb, | 317 | return nfc_data_exchange(dev, local->target_idx, skb, |
316 | nfc_llcp_recv, local); | 318 | nfc_llcp_recv, local); |
317 | } | 319 | } |
diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c index 90ef4a176819..c12c5ef3d036 100644 --- a/net/nfc/llcp/llcp.c +++ b/net/nfc/llcp/llcp.c | |||
@@ -56,7 +56,7 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen) | |||
56 | sk_for_each_safe(sk, node, tmp, &local->sockets.head) { | 56 | sk_for_each_safe(sk, node, tmp, &local->sockets.head) { |
57 | llcp_sock = nfc_llcp_sock(sk); | 57 | llcp_sock = nfc_llcp_sock(sk); |
58 | 58 | ||
59 | lock_sock(sk); | 59 | bh_lock_sock(sk); |
60 | 60 | ||
61 | if (sk->sk_state == LLCP_CONNECTED) | 61 | if (sk->sk_state == LLCP_CONNECTED) |
62 | nfc_put_device(llcp_sock->dev); | 62 | nfc_put_device(llcp_sock->dev); |
@@ -68,26 +68,26 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen) | |||
68 | list_for_each_entry_safe(lsk, n, &llcp_sock->accept_queue, | 68 | list_for_each_entry_safe(lsk, n, &llcp_sock->accept_queue, |
69 | accept_queue) { | 69 | accept_queue) { |
70 | accept_sk = &lsk->sk; | 70 | accept_sk = &lsk->sk; |
71 | lock_sock(accept_sk); | 71 | bh_lock_sock(accept_sk); |
72 | 72 | ||
73 | nfc_llcp_accept_unlink(accept_sk); | 73 | nfc_llcp_accept_unlink(accept_sk); |
74 | 74 | ||
75 | accept_sk->sk_state = LLCP_CLOSED; | 75 | accept_sk->sk_state = LLCP_CLOSED; |
76 | 76 | ||
77 | release_sock(accept_sk); | 77 | bh_unlock_sock(accept_sk); |
78 | 78 | ||
79 | sock_orphan(accept_sk); | 79 | sock_orphan(accept_sk); |
80 | } | 80 | } |
81 | 81 | ||
82 | if (listen == true) { | 82 | if (listen == true) { |
83 | release_sock(sk); | 83 | bh_unlock_sock(sk); |
84 | continue; | 84 | continue; |
85 | } | 85 | } |
86 | } | 86 | } |
87 | 87 | ||
88 | sk->sk_state = LLCP_CLOSED; | 88 | sk->sk_state = LLCP_CLOSED; |
89 | 89 | ||
90 | release_sock(sk); | 90 | bh_unlock_sock(sk); |
91 | 91 | ||
92 | sock_orphan(sk); | 92 | sock_orphan(sk); |
93 | 93 | ||
@@ -558,6 +558,46 @@ static void nfc_llcp_set_nrns(struct nfc_llcp_sock *sock, struct sk_buff *pdu) | |||
558 | sock->recv_ack_n = (sock->recv_n - 1) % 16; | 558 | sock->recv_ack_n = (sock->recv_n - 1) % 16; |
559 | } | 559 | } |
560 | 560 | ||
561 | void nfc_llcp_send_to_raw_sock(struct nfc_llcp_local *local, | ||
562 | struct sk_buff *skb, u8 direction) | ||
563 | { | ||
564 | struct hlist_node *node; | ||
565 | struct sk_buff *skb_copy = NULL, *nskb; | ||
566 | struct sock *sk; | ||
567 | u8 *data; | ||
568 | |||
569 | read_lock(&local->raw_sockets.lock); | ||
570 | |||
571 | sk_for_each(sk, node, &local->raw_sockets.head) { | ||
572 | if (sk->sk_state != LLCP_BOUND) | ||
573 | continue; | ||
574 | |||
575 | if (skb_copy == NULL) { | ||
576 | skb_copy = __pskb_copy(skb, NFC_LLCP_RAW_HEADER_SIZE, | ||
577 | GFP_ATOMIC); | ||
578 | |||
579 | if (skb_copy == NULL) | ||
580 | continue; | ||
581 | |||
582 | data = skb_push(skb_copy, NFC_LLCP_RAW_HEADER_SIZE); | ||
583 | |||
584 | data[0] = local->dev ? local->dev->idx : 0xFF; | ||
585 | data[1] = direction; | ||
586 | } | ||
587 | |||
588 | nskb = skb_clone(skb_copy, GFP_ATOMIC); | ||
589 | if (!nskb) | ||
590 | continue; | ||
591 | |||
592 | if (sock_queue_rcv_skb(sk, nskb)) | ||
593 | kfree_skb(nskb); | ||
594 | } | ||
595 | |||
596 | read_unlock(&local->raw_sockets.lock); | ||
597 | |||
598 | kfree_skb(skb_copy); | ||
599 | } | ||
600 | |||
561 | static void nfc_llcp_tx_work(struct work_struct *work) | 601 | static void nfc_llcp_tx_work(struct work_struct *work) |
562 | { | 602 | { |
563 | struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local, | 603 | struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local, |
@@ -578,6 +618,9 @@ static void nfc_llcp_tx_work(struct work_struct *work) | |||
578 | DUMP_PREFIX_OFFSET, 16, 1, | 618 | DUMP_PREFIX_OFFSET, 16, 1, |
579 | skb->data, skb->len, true); | 619 | skb->data, skb->len, true); |
580 | 620 | ||
621 | nfc_llcp_send_to_raw_sock(local, skb, | ||
622 | NFC_LLCP_DIRECTION_TX); | ||
623 | |||
581 | ret = nfc_data_exchange(local->dev, local->target_idx, | 624 | ret = nfc_data_exchange(local->dev, local->target_idx, |
582 | skb, nfc_llcp_recv, local); | 625 | skb, nfc_llcp_recv, local); |
583 | 626 | ||
@@ -1022,6 +1065,8 @@ static void nfc_llcp_rx_work(struct work_struct *work) | |||
1022 | print_hex_dump(KERN_DEBUG, "LLCP Rx: ", DUMP_PREFIX_OFFSET, | 1065 | print_hex_dump(KERN_DEBUG, "LLCP Rx: ", DUMP_PREFIX_OFFSET, |
1023 | 16, 1, skb->data, skb->len, true); | 1066 | 16, 1, skb->data, skb->len, true); |
1024 | 1067 | ||
1068 | nfc_llcp_send_to_raw_sock(local, skb, NFC_LLCP_DIRECTION_RX); | ||
1069 | |||
1025 | switch (ptype) { | 1070 | switch (ptype) { |
1026 | case LLCP_PDU_SYMM: | 1071 | case LLCP_PDU_SYMM: |
1027 | pr_debug("SYMM\n"); | 1072 | pr_debug("SYMM\n"); |
@@ -1156,8 +1201,9 @@ int nfc_llcp_register_device(struct nfc_dev *ndev) | |||
1156 | 1201 | ||
1157 | INIT_WORK(&local->timeout_work, nfc_llcp_timeout_work); | 1202 | INIT_WORK(&local->timeout_work, nfc_llcp_timeout_work); |
1158 | 1203 | ||
1159 | local->sockets.lock = __RW_LOCK_UNLOCKED(local->sockets.lock); | 1204 | rwlock_init(&local->sockets.lock); |
1160 | local->connecting_sockets.lock = __RW_LOCK_UNLOCKED(local->connecting_sockets.lock); | 1205 | rwlock_init(&local->connecting_sockets.lock); |
1206 | rwlock_init(&local->raw_sockets.lock); | ||
1161 | 1207 | ||
1162 | nfc_llcp_build_gb(local); | 1208 | nfc_llcp_build_gb(local); |
1163 | 1209 | ||
diff --git a/net/nfc/llcp/llcp.h b/net/nfc/llcp/llcp.h index af395c9ceb03..fdb2d24e60bd 100644 --- a/net/nfc/llcp/llcp.h +++ b/net/nfc/llcp/llcp.h | |||
@@ -86,6 +86,7 @@ struct nfc_llcp_local { | |||
86 | /* sockets array */ | 86 | /* sockets array */ |
87 | struct llcp_sock_list sockets; | 87 | struct llcp_sock_list sockets; |
88 | struct llcp_sock_list connecting_sockets; | 88 | struct llcp_sock_list connecting_sockets; |
89 | struct llcp_sock_list raw_sockets; | ||
89 | }; | 90 | }; |
90 | 91 | ||
91 | struct nfc_llcp_sock { | 92 | struct nfc_llcp_sock { |
@@ -184,6 +185,8 @@ u8 nfc_llcp_get_sdp_ssap(struct nfc_llcp_local *local, | |||
184 | u8 nfc_llcp_get_local_ssap(struct nfc_llcp_local *local); | 185 | u8 nfc_llcp_get_local_ssap(struct nfc_llcp_local *local); |
185 | void nfc_llcp_put_ssap(struct nfc_llcp_local *local, u8 ssap); | 186 | void nfc_llcp_put_ssap(struct nfc_llcp_local *local, u8 ssap); |
186 | int nfc_llcp_queue_i_frames(struct nfc_llcp_sock *sock); | 187 | int nfc_llcp_queue_i_frames(struct nfc_llcp_sock *sock); |
188 | void nfc_llcp_send_to_raw_sock(struct nfc_llcp_local *local, | ||
189 | struct sk_buff *skb, u8 direction); | ||
187 | 190 | ||
188 | /* Sock API */ | 191 | /* Sock API */ |
189 | struct sock *nfc_llcp_sock_alloc(struct socket *sock, int type, gfp_t gfp); | 192 | struct sock *nfc_llcp_sock_alloc(struct socket *sock, int type, gfp_t gfp); |
diff --git a/net/nfc/llcp/sock.c b/net/nfc/llcp/sock.c index 6e188d4020ba..40f056debf9a 100644 --- a/net/nfc/llcp/sock.c +++ b/net/nfc/llcp/sock.c | |||
@@ -142,6 +142,60 @@ error: | |||
142 | return ret; | 142 | return ret; |
143 | } | 143 | } |
144 | 144 | ||
145 | static int llcp_raw_sock_bind(struct socket *sock, struct sockaddr *addr, | ||
146 | int alen) | ||
147 | { | ||
148 | struct sock *sk = sock->sk; | ||
149 | struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk); | ||
150 | struct nfc_llcp_local *local; | ||
151 | struct nfc_dev *dev; | ||
152 | struct sockaddr_nfc_llcp llcp_addr; | ||
153 | int len, ret = 0; | ||
154 | |||
155 | if (!addr || addr->sa_family != AF_NFC) | ||
156 | return -EINVAL; | ||
157 | |||
158 | pr_debug("sk %p addr %p family %d\n", sk, addr, addr->sa_family); | ||
159 | |||
160 | memset(&llcp_addr, 0, sizeof(llcp_addr)); | ||
161 | len = min_t(unsigned int, sizeof(llcp_addr), alen); | ||
162 | memcpy(&llcp_addr, addr, len); | ||
163 | |||
164 | lock_sock(sk); | ||
165 | |||
166 | if (sk->sk_state != LLCP_CLOSED) { | ||
167 | ret = -EBADFD; | ||
168 | goto error; | ||
169 | } | ||
170 | |||
171 | dev = nfc_get_device(llcp_addr.dev_idx); | ||
172 | if (dev == NULL) { | ||
173 | ret = -ENODEV; | ||
174 | goto error; | ||
175 | } | ||
176 | |||
177 | local = nfc_llcp_find_local(dev); | ||
178 | if (local == NULL) { | ||
179 | ret = -ENODEV; | ||
180 | goto put_dev; | ||
181 | } | ||
182 | |||
183 | llcp_sock->dev = dev; | ||
184 | llcp_sock->local = nfc_llcp_local_get(local); | ||
185 | llcp_sock->nfc_protocol = llcp_addr.nfc_protocol; | ||
186 | |||
187 | nfc_llcp_sock_link(&local->raw_sockets, sk); | ||
188 | |||
189 | sk->sk_state = LLCP_BOUND; | ||
190 | |||
191 | put_dev: | ||
192 | nfc_put_device(dev); | ||
193 | |||
194 | error: | ||
195 | release_sock(sk); | ||
196 | return ret; | ||
197 | } | ||
198 | |||
145 | static int llcp_sock_listen(struct socket *sock, int backlog) | 199 | static int llcp_sock_listen(struct socket *sock, int backlog) |
146 | { | 200 | { |
147 | struct sock *sk = sock->sk; | 201 | struct sock *sk = sock->sk; |
@@ -418,7 +472,10 @@ static int llcp_sock_release(struct socket *sock) | |||
418 | 472 | ||
419 | release_sock(sk); | 473 | release_sock(sk); |
420 | 474 | ||
421 | nfc_llcp_sock_unlink(&local->sockets, sk); | 475 | if (sock->type == SOCK_RAW) |
476 | nfc_llcp_sock_unlink(&local->raw_sockets, sk); | ||
477 | else | ||
478 | nfc_llcp_sock_unlink(&local->sockets, sk); | ||
422 | 479 | ||
423 | out: | 480 | out: |
424 | sock_orphan(sk); | 481 | sock_orphan(sk); |
@@ -614,7 +671,7 @@ static int llcp_sock_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
614 | if (!(flags & MSG_PEEK)) { | 671 | if (!(flags & MSG_PEEK)) { |
615 | 672 | ||
616 | /* SOCK_STREAM: re-queue skb if it contains unreceived data */ | 673 | /* SOCK_STREAM: re-queue skb if it contains unreceived data */ |
617 | if (sk->sk_type == SOCK_STREAM) { | 674 | if (sk->sk_type == SOCK_STREAM || sk->sk_type == SOCK_RAW) { |
618 | skb_pull(skb, copied); | 675 | skb_pull(skb, copied); |
619 | if (skb->len) { | 676 | if (skb->len) { |
620 | skb_queue_head(&sk->sk_receive_queue, skb); | 677 | skb_queue_head(&sk->sk_receive_queue, skb); |
@@ -655,6 +712,26 @@ static const struct proto_ops llcp_sock_ops = { | |||
655 | .mmap = sock_no_mmap, | 712 | .mmap = sock_no_mmap, |
656 | }; | 713 | }; |
657 | 714 | ||
715 | static const struct proto_ops llcp_rawsock_ops = { | ||
716 | .family = PF_NFC, | ||
717 | .owner = THIS_MODULE, | ||
718 | .bind = llcp_raw_sock_bind, | ||
719 | .connect = sock_no_connect, | ||
720 | .release = llcp_sock_release, | ||
721 | .socketpair = sock_no_socketpair, | ||
722 | .accept = sock_no_accept, | ||
723 | .getname = llcp_sock_getname, | ||
724 | .poll = llcp_sock_poll, | ||
725 | .ioctl = sock_no_ioctl, | ||
726 | .listen = sock_no_listen, | ||
727 | .shutdown = sock_no_shutdown, | ||
728 | .setsockopt = sock_no_setsockopt, | ||
729 | .getsockopt = sock_no_getsockopt, | ||
730 | .sendmsg = sock_no_sendmsg, | ||
731 | .recvmsg = llcp_sock_recvmsg, | ||
732 | .mmap = sock_no_mmap, | ||
733 | }; | ||
734 | |||
658 | static void llcp_sock_destruct(struct sock *sk) | 735 | static void llcp_sock_destruct(struct sock *sk) |
659 | { | 736 | { |
660 | struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk); | 737 | struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk); |
@@ -732,10 +809,15 @@ static int llcp_sock_create(struct net *net, struct socket *sock, | |||
732 | 809 | ||
733 | pr_debug("%p\n", sock); | 810 | pr_debug("%p\n", sock); |
734 | 811 | ||
735 | if (sock->type != SOCK_STREAM && sock->type != SOCK_DGRAM) | 812 | if (sock->type != SOCK_STREAM && |
813 | sock->type != SOCK_DGRAM && | ||
814 | sock->type != SOCK_RAW) | ||
736 | return -ESOCKTNOSUPPORT; | 815 | return -ESOCKTNOSUPPORT; |
737 | 816 | ||
738 | sock->ops = &llcp_sock_ops; | 817 | if (sock->type == SOCK_RAW) |
818 | sock->ops = &llcp_rawsock_ops; | ||
819 | else | ||
820 | sock->ops = &llcp_sock_ops; | ||
739 | 821 | ||
740 | sk = nfc_llcp_sock_alloc(sock, sock->type, GFP_ATOMIC); | 822 | sk = nfc_llcp_sock_alloc(sock, sock->type, GFP_ATOMIC); |
741 | if (sk == NULL) | 823 | if (sk == NULL) |
diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c index 4c51714ee741..baa6af9500df 100644 --- a/net/nfc/netlink.c +++ b/net/nfc/netlink.c | |||
@@ -761,31 +761,63 @@ static struct genl_ops nfc_genl_ops[] = { | |||
761 | }, | 761 | }, |
762 | }; | 762 | }; |
763 | 763 | ||
764 | static int nfc_genl_rcv_nl_event(struct notifier_block *this, | 764 | |
765 | unsigned long event, void *ptr) | 765 | struct urelease_work { |
766 | struct work_struct w; | ||
767 | int pid; | ||
768 | }; | ||
769 | |||
770 | static void nfc_urelease_event_work(struct work_struct *work) | ||
766 | { | 771 | { |
767 | struct netlink_notify *n = ptr; | 772 | struct urelease_work *w = container_of(work, struct urelease_work, w); |
768 | struct class_dev_iter iter; | 773 | struct class_dev_iter iter; |
769 | struct nfc_dev *dev; | 774 | struct nfc_dev *dev; |
770 | 775 | ||
771 | if (event != NETLINK_URELEASE || n->protocol != NETLINK_GENERIC) | 776 | pr_debug("pid %d\n", w->pid); |
772 | goto out; | ||
773 | 777 | ||
774 | pr_debug("NETLINK_URELEASE event from id %d\n", n->pid); | 778 | mutex_lock(&nfc_devlist_mutex); |
775 | 779 | ||
776 | nfc_device_iter_init(&iter); | 780 | nfc_device_iter_init(&iter); |
777 | dev = nfc_device_iter_next(&iter); | 781 | dev = nfc_device_iter_next(&iter); |
778 | 782 | ||
779 | while (dev) { | 783 | while (dev) { |
780 | if (dev->genl_data.poll_req_pid == n->pid) { | 784 | mutex_lock(&dev->genl_data.genl_data_mutex); |
785 | |||
786 | if (dev->genl_data.poll_req_pid == w->pid) { | ||
781 | nfc_stop_poll(dev); | 787 | nfc_stop_poll(dev); |
782 | dev->genl_data.poll_req_pid = 0; | 788 | dev->genl_data.poll_req_pid = 0; |
783 | } | 789 | } |
790 | |||
791 | mutex_unlock(&dev->genl_data.genl_data_mutex); | ||
792 | |||
784 | dev = nfc_device_iter_next(&iter); | 793 | dev = nfc_device_iter_next(&iter); |
785 | } | 794 | } |
786 | 795 | ||
787 | nfc_device_iter_exit(&iter); | 796 | nfc_device_iter_exit(&iter); |
788 | 797 | ||
798 | mutex_unlock(&nfc_devlist_mutex); | ||
799 | |||
800 | kfree(w); | ||
801 | } | ||
802 | |||
803 | static int nfc_genl_rcv_nl_event(struct notifier_block *this, | ||
804 | unsigned long event, void *ptr) | ||
805 | { | ||
806 | struct netlink_notify *n = ptr; | ||
807 | struct urelease_work *w; | ||
808 | |||
809 | if (event != NETLINK_URELEASE || n->protocol != NETLINK_GENERIC) | ||
810 | goto out; | ||
811 | |||
812 | pr_debug("NETLINK_URELEASE event from id %d\n", n->pid); | ||
813 | |||
814 | w = kmalloc(sizeof(*w), GFP_ATOMIC); | ||
815 | if (w) { | ||
816 | INIT_WORK((struct work_struct *) w, nfc_urelease_event_work); | ||
817 | w->pid = n->pid; | ||
818 | schedule_work((struct work_struct *) w); | ||
819 | } | ||
820 | |||
789 | out: | 821 | out: |
790 | return NOTIFY_DONE; | 822 | return NOTIFY_DONE; |
791 | } | 823 | } |