net/l2tp/l2tp_ppp.c

Source file repositories/reference/linux-study-clean/net/l2tp/l2tp_ppp.c

File Facts

System
Linux kernel
Corpus path
net/l2tp/l2tp_ppp.c
Extension
.c
Size
43354 bytes
Lines
1731
Domain
Networking Core
Bucket
Sockets, Protocols, Packet Path, And Network Policy
Inferred role
Networking Core: operation-table or driver-model contract
Status
pattern 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

static const struct proto_ops pppol2tp_ops;

/* Retrieves the pppol2tp socket associated to a session. */
static struct sock *pppol2tp_session_get_sock(struct l2tp_session *session)
{
	struct pppol2tp_session *ps = l2tp_session_priv(session);

	return rcu_dereference(ps->sk);
}

/* Helpers to obtain tunnel/session contexts from sockets.
 */
static struct l2tp_session *pppol2tp_sock_to_session(struct sock *sk)
{
	struct l2tp_session *session;

	if (!sk)
		return NULL;

	rcu_read_lock();
	session = rcu_dereference_sk_user_data(sk);
	if (session && refcount_inc_not_zero(&session->ref_count)) {
		rcu_read_unlock();
		WARN_ON_ONCE(session->magic != L2TP_SESSION_MAGIC);
		return session;
	}
	rcu_read_unlock();

	return NULL;
}

/*****************************************************************************
 * Receive data handling
 *****************************************************************************/

/* Receive message. This is the recvmsg for the PPPoL2TP socket.
 */
static int pppol2tp_recvmsg(struct socket *sock, struct msghdr *msg,
			    size_t len, int flags)
{
	int err;
	struct sk_buff *skb;
	struct sock *sk = sock->sk;

	err = -EIO;
	if (sk->sk_state & PPPOX_BOUND)
		goto end;

	err = 0;
	skb = skb_recv_datagram(sk, flags, &err);
	if (!skb)
		goto end;

	if (len > skb->len)
		len = skb->len;
	else if (len < skb->len)
		msg->msg_flags |= MSG_TRUNC;

	err = skb_copy_datagram_msg(skb, 0, msg, len);
	if (likely(err == 0))
		err = len;

	kfree_skb(skb);
end:
	return err;
}

static void pppol2tp_recv(struct l2tp_session *session, struct sk_buff *skb, int data_len)
{
	struct sock *sk;

	/* If the socket is bound, send it in to PPP's input queue. Otherwise
	 * queue it on the session socket.
	 */
	rcu_read_lock();
	sk = pppol2tp_session_get_sock(session);
	if (!sk)
		goto no_sock;

	/* If the first two bytes are 0xFF03, consider that it is the PPP's
	 * Address and Control fields and skip them. The L2TP module has always
	 * worked this way, although, in theory, the use of these fields should
	 * be negotiated and handled at the PPP layer. These fields are
	 * constant: 0xFF is the All-Stations Address and 0x03 the Unnumbered
	 * Information command with Poll/Final bit set to zero (RFC 1662).
	 */
	if (pskb_may_pull(skb, 2) && skb->data[0] == PPP_ALLSTATIONS &&
	    skb->data[1] == PPP_UI)
		skb_pull(skb, 2);

Annotation

Implementation Notes