diff options
Diffstat (limited to 'net/nfc/llcp/llcp.c')
-rw-r--r-- | net/nfc/llcp/llcp.c | 66 |
1 files changed, 51 insertions, 15 deletions
diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c index 7f8266dd14cb..ee25f25f0cd6 100644 --- a/net/nfc/llcp/llcp.c +++ b/net/nfc/llcp/llcp.c | |||
@@ -68,7 +68,8 @@ static void nfc_llcp_socket_purge(struct nfc_llcp_sock *sock) | |||
68 | } | 68 | } |
69 | } | 69 | } |
70 | 70 | ||
71 | static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen) | 71 | static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen, |
72 | int err) | ||
72 | { | 73 | { |
73 | struct sock *sk; | 74 | struct sock *sk; |
74 | struct hlist_node *tmp; | 75 | struct hlist_node *tmp; |
@@ -100,11 +101,12 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen) | |||
100 | 101 | ||
101 | nfc_llcp_accept_unlink(accept_sk); | 102 | nfc_llcp_accept_unlink(accept_sk); |
102 | 103 | ||
104 | if (err) | ||
105 | accept_sk->sk_err = err; | ||
103 | accept_sk->sk_state = LLCP_CLOSED; | 106 | accept_sk->sk_state = LLCP_CLOSED; |
107 | accept_sk->sk_state_change(sk); | ||
104 | 108 | ||
105 | bh_unlock_sock(accept_sk); | 109 | bh_unlock_sock(accept_sk); |
106 | |||
107 | sock_orphan(accept_sk); | ||
108 | } | 110 | } |
109 | 111 | ||
110 | if (listen == true) { | 112 | if (listen == true) { |
@@ -123,16 +125,45 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen) | |||
123 | continue; | 125 | continue; |
124 | } | 126 | } |
125 | 127 | ||
128 | if (err) | ||
129 | sk->sk_err = err; | ||
126 | sk->sk_state = LLCP_CLOSED; | 130 | sk->sk_state = LLCP_CLOSED; |
131 | sk->sk_state_change(sk); | ||
127 | 132 | ||
128 | bh_unlock_sock(sk); | 133 | bh_unlock_sock(sk); |
129 | 134 | ||
130 | sock_orphan(sk); | ||
131 | |||
132 | sk_del_node_init(sk); | 135 | sk_del_node_init(sk); |
133 | } | 136 | } |
134 | 137 | ||
135 | write_unlock(&local->sockets.lock); | 138 | write_unlock(&local->sockets.lock); |
139 | |||
140 | /* | ||
141 | * If we want to keep the listening sockets alive, | ||
142 | * we don't touch the RAW ones. | ||
143 | */ | ||
144 | if (listen == true) | ||
145 | return; | ||
146 | |||
147 | write_lock(&local->raw_sockets.lock); | ||
148 | |||
149 | sk_for_each_safe(sk, tmp, &local->raw_sockets.head) { | ||
150 | llcp_sock = nfc_llcp_sock(sk); | ||
151 | |||
152 | bh_lock_sock(sk); | ||
153 | |||
154 | nfc_llcp_socket_purge(llcp_sock); | ||
155 | |||
156 | if (err) | ||
157 | sk->sk_err = err; | ||
158 | sk->sk_state = LLCP_CLOSED; | ||
159 | sk->sk_state_change(sk); | ||
160 | |||
161 | bh_unlock_sock(sk); | ||
162 | |||
163 | sk_del_node_init(sk); | ||
164 | } | ||
165 | |||
166 | write_unlock(&local->raw_sockets.lock); | ||
136 | } | 167 | } |
137 | 168 | ||
138 | struct nfc_llcp_local *nfc_llcp_local_get(struct nfc_llcp_local *local) | 169 | struct nfc_llcp_local *nfc_llcp_local_get(struct nfc_llcp_local *local) |
@@ -142,20 +173,25 @@ struct nfc_llcp_local *nfc_llcp_local_get(struct nfc_llcp_local *local) | |||
142 | return local; | 173 | return local; |
143 | } | 174 | } |
144 | 175 | ||
145 | static void local_release(struct kref *ref) | 176 | static void local_cleanup(struct nfc_llcp_local *local, bool listen) |
146 | { | 177 | { |
147 | struct nfc_llcp_local *local; | 178 | nfc_llcp_socket_release(local, listen, ENXIO); |
148 | |||
149 | local = container_of(ref, struct nfc_llcp_local, ref); | ||
150 | |||
151 | list_del(&local->list); | ||
152 | nfc_llcp_socket_release(local, false); | ||
153 | del_timer_sync(&local->link_timer); | 179 | del_timer_sync(&local->link_timer); |
154 | skb_queue_purge(&local->tx_queue); | 180 | skb_queue_purge(&local->tx_queue); |
155 | cancel_work_sync(&local->tx_work); | 181 | cancel_work_sync(&local->tx_work); |
156 | cancel_work_sync(&local->rx_work); | 182 | cancel_work_sync(&local->rx_work); |
157 | cancel_work_sync(&local->timeout_work); | 183 | cancel_work_sync(&local->timeout_work); |
158 | kfree_skb(local->rx_pending); | 184 | kfree_skb(local->rx_pending); |
185 | } | ||
186 | |||
187 | static void local_release(struct kref *ref) | ||
188 | { | ||
189 | struct nfc_llcp_local *local; | ||
190 | |||
191 | local = container_of(ref, struct nfc_llcp_local, ref); | ||
192 | |||
193 | list_del(&local->list); | ||
194 | local_cleanup(local, false); | ||
159 | kfree(local); | 195 | kfree(local); |
160 | } | 196 | } |
161 | 197 | ||
@@ -785,7 +821,6 @@ static void nfc_llcp_recv_ui(struct nfc_llcp_local *local, | |||
785 | skb_get(skb); | 821 | skb_get(skb); |
786 | } else { | 822 | } else { |
787 | pr_err("Receive queue is full\n"); | 823 | pr_err("Receive queue is full\n"); |
788 | kfree_skb(skb); | ||
789 | } | 824 | } |
790 | 825 | ||
791 | nfc_llcp_sock_put(llcp_sock); | 826 | nfc_llcp_sock_put(llcp_sock); |
@@ -986,7 +1021,6 @@ static void nfc_llcp_recv_hdlc(struct nfc_llcp_local *local, | |||
986 | skb_get(skb); | 1021 | skb_get(skb); |
987 | } else { | 1022 | } else { |
988 | pr_err("Receive queue is full\n"); | 1023 | pr_err("Receive queue is full\n"); |
989 | kfree_skb(skb); | ||
990 | } | 1024 | } |
991 | } | 1025 | } |
992 | 1026 | ||
@@ -1348,7 +1382,7 @@ void nfc_llcp_mac_is_down(struct nfc_dev *dev) | |||
1348 | return; | 1382 | return; |
1349 | 1383 | ||
1350 | /* Close and purge all existing sockets */ | 1384 | /* Close and purge all existing sockets */ |
1351 | nfc_llcp_socket_release(local, true); | 1385 | nfc_llcp_socket_release(local, true, 0); |
1352 | } | 1386 | } |
1353 | 1387 | ||
1354 | void nfc_llcp_mac_is_up(struct nfc_dev *dev, u32 target_idx, | 1388 | void nfc_llcp_mac_is_up(struct nfc_dev *dev, u32 target_idx, |
@@ -1427,6 +1461,8 @@ void nfc_llcp_unregister_device(struct nfc_dev *dev) | |||
1427 | return; | 1461 | return; |
1428 | } | 1462 | } |
1429 | 1463 | ||
1464 | local_cleanup(local, false); | ||
1465 | |||
1430 | nfc_llcp_local_put(local); | 1466 | nfc_llcp_local_put(local); |
1431 | } | 1467 | } |
1432 | 1468 | ||