net/nfc/llcp_core.c

Source file repositories/reference/linux-study-clean/net/nfc/llcp_core.c

File Facts

System
Linux kernel
Corpus path
net/nfc/llcp_core.c
Extension
.c
Size
36661 bytes
Lines
1713
Domain
Networking Core
Bucket
Sockets, Protocols, Packet Path, And Network Policy
Inferred role
Networking Core: implementation source
Status
source implementation candidate

Why This File Exists

Networking stack implementation surface: socket APIs, protocol dispatch, packet flow, routing, filtering, and network namespaces.

Dependency Surface

Detected Declarations

Annotated Snippet

if (sk->sk_state == LLCP_LISTEN) {
			struct nfc_llcp_sock *lsk, *n;
			struct sock *accept_sk;

			list_for_each_entry_safe(lsk, n,
						 &llcp_sock->accept_queue,
						 accept_queue) {
				accept_sk = &lsk->sk;
				bh_lock_sock(accept_sk);

				nfc_llcp_accept_unlink(accept_sk);

				if (err)
					accept_sk->sk_err = err;
				accept_sk->sk_state = LLCP_CLOSED;
				accept_sk->sk_state_change(sk);

				bh_unlock_sock(accept_sk);
			}
		}

		if (err)
			sk->sk_err = err;
		sk->sk_state = LLCP_CLOSED;
		sk->sk_state_change(sk);

		bh_unlock_sock(sk);

		sk_del_node_init(sk);
	}

	write_unlock(&local->sockets.lock);

	/* If we still have a device, we keep the RAW sockets alive */
	if (device == true)
		return;

	write_lock(&local->raw_sockets.lock);

	sk_for_each_safe(sk, tmp, &local->raw_sockets.head) {
		llcp_sock = nfc_llcp_sock(sk);

		bh_lock_sock(sk);

		nfc_llcp_socket_purge(llcp_sock);

		if (err)
			sk->sk_err = err;
		sk->sk_state = LLCP_CLOSED;
		sk->sk_state_change(sk);

		bh_unlock_sock(sk);

		sk_del_node_init(sk);
	}

	write_unlock(&local->raw_sockets.lock);
}

static struct nfc_llcp_local *nfc_llcp_local_get(struct nfc_llcp_local *local)
{
	/* Since using nfc_llcp_local may result in usage of nfc_dev, whenever
	 * we hold a reference to local, we also need to hold a reference to
	 * the device to avoid UAF.
	 */
	if (!nfc_get_device(local->dev->idx))
		return NULL;

	kref_get(&local->ref);

	return local;
}

static void local_cleanup(struct nfc_llcp_local *local)
{
	nfc_llcp_socket_release(local, false, ENXIO);
	timer_delete_sync(&local->link_timer);
	skb_queue_purge(&local->tx_queue);
	cancel_work_sync(&local->tx_work);
	cancel_work_sync(&local->rx_work);
	cancel_work_sync(&local->timeout_work);
	kfree_skb(local->rx_pending);
	local->rx_pending = NULL;
	timer_delete_sync(&local->sdreq_timer);
	cancel_work_sync(&local->sdreq_timeout_work);
	nfc_llcp_free_sdp_tlv_list(&local->pending_sdreqs);
}

static void local_release(struct kref *ref)
{

Annotation

Implementation Notes