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 | ||
