pppol2tp.c

来自「linux 内核源代码」· C语言 代码 · 共 2,472 行 · 第 1/5 页

C
2,472
字号
	tunnel = pppol2tp_sock_to_tunnel(sock);	if (tunnel == NULL)		goto no_tunnel;	/* UDP always verifies the packet length. */	__skb_pull(skb, sizeof(struct udphdr));	/* Short packet? */	if (!pskb_may_pull(skb, 12)) {		PRINTK(tunnel->debug, PPPOL2TP_MSG_DATA, KERN_INFO,		       "%s: recv short packet (len=%d)\n", tunnel->name, skb->len);		goto error;	}	/* Point to L2TP header */	optr = ptr = skb->data;	/* Get L2TP header flags */	hdrflags = ntohs(*(__be16*)ptr);	/* Trace packet contents, if enabled */	if (tunnel->debug & PPPOL2TP_MSG_DATA) {		length = min(16u, skb->len);		if (!pskb_may_pull(skb, length))			goto error;		printk(KERN_DEBUG "%s: recv: ", tunnel->name);		offset = 0;		do {			printk(" %02X", ptr[offset]);		} while (++offset < length);		printk("\n");	}	/* Get length of L2TP packet */	length = skb->len;	/* If type is control packet, it is handled by userspace. */	if (hdrflags & L2TP_HDRFLAG_T) {		PRINTK(tunnel->debug, PPPOL2TP_MSG_DATA, KERN_DEBUG,		       "%s: recv control packet, len=%d\n", tunnel->name, length);		goto error;	}	/* Skip flags */	ptr += 2;	/* If length is present, skip it */	if (hdrflags & L2TP_HDRFLAG_L)		ptr += 2;	/* Extract tunnel and session ID */	tunnel_id = ntohs(*(__be16 *) ptr);	ptr += 2;	session_id = ntohs(*(__be16 *) ptr);	ptr += 2;	/* Find the session context */	session = pppol2tp_session_find(tunnel, session_id);	if (!session) {		/* Not found? Pass to userspace to deal with */		PRINTK(tunnel->debug, PPPOL2TP_MSG_DATA, KERN_INFO,		       "%s: no socket found (%hu/%hu). Passing up.\n",		       tunnel->name, tunnel_id, session_id);		goto error;	}	sock_hold(session->sock);	/* The ref count on the socket was increased by the above call since	 * we now hold a pointer to the session. Take care to do sock_put()	 * when exiting this function from now on...	 */	/* Handle the optional sequence numbers.  If we are the LAC,	 * enable/disable sequence numbers under the control of the LNS.  If	 * no sequence numbers present but we were expecting them, discard	 * frame.	 */	if (hdrflags & L2TP_HDRFLAG_S) {		u16 ns, nr;		ns = ntohs(*(__be16 *) ptr);		ptr += 2;		nr = ntohs(*(__be16 *) ptr);		ptr += 2;		/* Received a packet with sequence numbers. If we're the LNS,		 * check if we sre sending sequence numbers and if not,		 * configure it so.		 */		if ((!session->lns_mode) && (!session->send_seq)) {			PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_INFO,			       "%s: requested to enable seq numbers by LNS\n",			       session->name);			session->send_seq = -1;		}		/* Store L2TP info in the skb */		PPPOL2TP_SKB_CB(skb)->ns = ns;		PPPOL2TP_SKB_CB(skb)->nr = nr;		PPPOL2TP_SKB_CB(skb)->has_seq = 1;		PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_DEBUG,		       "%s: recv data ns=%hu, nr=%hu, session nr=%hu\n",		       session->name, ns, nr, session->nr);	} else {		/* No sequence numbers.		 * If user has configured mandatory sequence numbers, discard.		 */		if (session->recv_seq) {			PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_WARNING,			       "%s: recv data has no seq numbers when required. "			       "Discarding\n", session->name);			session->stats.rx_seq_discards++;			goto discard;		}		/* If we're the LAC and we're sending sequence numbers, the		 * LNS has requested that we no longer send sequence numbers.		 * If we're the LNS and we're sending sequence numbers, the		 * LAC is broken. Discard the frame.		 */		if ((!session->lns_mode) && (session->send_seq)) {			PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_INFO,			       "%s: requested to disable seq numbers by LNS\n",			       session->name);			session->send_seq = 0;		} else if (session->send_seq) {			PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_WARNING,			       "%s: recv data has no seq numbers when required. "			       "Discarding\n", session->name);			session->stats.rx_seq_discards++;			goto discard;		}		/* Store L2TP info in the skb */		PPPOL2TP_SKB_CB(skb)->has_seq = 0;	}	/* If offset bit set, skip it. */	if (hdrflags & L2TP_HDRFLAG_O) {		offset = ntohs(*(__be16 *)ptr);		ptr += 2 + offset;	}	offset = ptr - optr;	if (!pskb_may_pull(skb, offset))		goto discard;	__skb_pull(skb, offset);	/* Skip PPP header, if present.	 In testing, Microsoft L2TP clients	 * don't send the PPP header (PPP header compression enabled), but	 * other clients can include the header. So we cope with both cases	 * here. The PPP header is always FF03 when using L2TP.	 *	 * Note that skb->data[] isn't dereferenced from a u16 ptr here since	 * the field may be unaligned.	 */	if (!pskb_may_pull(skb, 2))		goto discard;	if ((skb->data[0] == 0xff) && (skb->data[1] == 0x03))		skb_pull(skb, 2);	/* Prepare skb for adding to the session's reorder_q.  Hold	 * packets for max reorder_timeout or 1 second if not	 * reordering.	 */	PPPOL2TP_SKB_CB(skb)->length = length;	PPPOL2TP_SKB_CB(skb)->expires = jiffies +		(session->reorder_timeout ? session->reorder_timeout : HZ);	/* Add packet to the session's receive queue. Reordering is done here, if	 * enabled. Saved L2TP protocol info is stored in skb->sb[].	 */	if (PPPOL2TP_SKB_CB(skb)->has_seq) {		if (session->reorder_timeout != 0) {			/* Packet reordering enabled. Add skb to session's			 * reorder queue, in order of ns.			 */			pppol2tp_recv_queue_skb(session, skb);		} else {			/* Packet reordering disabled. Discard out-of-sequence			 * packets			 */			if (PPPOL2TP_SKB_CB(skb)->ns != session->nr) {				session->stats.rx_seq_discards++;				PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_DEBUG,				       "%s: oos pkt %hu len %d discarded, "				       "waiting for %hu, reorder_q_len=%d\n",				       session->name, PPPOL2TP_SKB_CB(skb)->ns,				       PPPOL2TP_SKB_CB(skb)->length, session->nr,				       skb_queue_len(&session->reorder_q));				goto discard;			}			skb_queue_tail(&session->reorder_q, skb);		}	} else {		/* No sequence numbers. Add the skb to the tail of the		 * reorder queue. This ensures that it will be		 * delivered after all previous sequenced skbs.		 */		skb_queue_tail(&session->reorder_q, skb);	}	/* Try to dequeue as many skbs from reorder_q as we can. */	pppol2tp_recv_dequeue(session);	return 0;discard:	session->stats.rx_errors++;	kfree_skb(skb);	sock_put(session->sock);	return 0;error:	/* Put UDP header back */	__skb_push(skb, sizeof(struct udphdr));no_tunnel:	return 1;}/* UDP encapsulation receive handler. See net/ipv4/udp.c. * Return codes: * 0 : success. * <0: error * >0: skb should be passed up to userspace as UDP. */static int pppol2tp_udp_encap_recv(struct sock *sk, struct sk_buff *skb){	struct pppol2tp_tunnel *tunnel;	tunnel = pppol2tp_sock_to_tunnel(sk);	if (tunnel == NULL)		goto pass_up;	PRINTK(tunnel->debug, PPPOL2TP_MSG_DATA, KERN_DEBUG,	       "%s: received %d bytes\n", tunnel->name, skb->len);	if (pppol2tp_recv_core(sk, skb))		goto pass_up;	return 0;pass_up:	return 1;}/* Receive message. This is the recvmsg for the PPPoL2TP socket. */static int pppol2tp_recvmsg(struct kiocb *iocb, 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;	msg->msg_namelen = 0;	err = 0;	skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,				flags & MSG_DONTWAIT, &err);	if (skb) {		err = memcpy_toiovec(msg->msg_iov, (unsigned char *) skb->data,				     skb->len);		if (err < 0)			goto do_skb_free;		err = skb->len;	}do_skb_free:	kfree_skb(skb);end:	return err;}/************************************************************************ * Transmit handling ***********************************************************************//* Tell how big L2TP headers are for a particular session. This * depends on whether sequence numbers are being used. */static inline int pppol2tp_l2tp_header_len(struct pppol2tp_session *session){	if (session->send_seq)		return PPPOL2TP_L2TP_HDR_SIZE_SEQ;	return PPPOL2TP_L2TP_HDR_SIZE_NOSEQ;}/* Build an L2TP header for the session into the buffer provided. */static void pppol2tp_build_l2tp_header(struct pppol2tp_session *session,				       void *buf){	__be16 *bufp = buf;	u16 flags = L2TP_HDR_VER;	if (session->send_seq)		flags |= L2TP_HDRFLAG_S;	/* Setup L2TP header.	 * FIXME: Can this ever be unaligned? Is direct dereferencing of	 * 16-bit header fields safe here for all architectures?	 */	*bufp++ = htons(flags);	*bufp++ = htons(session->tunnel_addr.d_tunnel);	*bufp++ = htons(session->tunnel_addr.d_session);	if (session->send_seq) {		*bufp++ = htons(session->ns);		*bufp++ = 0;		session->ns++;		PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_DEBUG,		       "%s: updated ns to %hu\n", session->name, session->ns);	}}/* This is the sendmsg for the PPPoL2TP pppol2tp_session socket.  We come here * when a user application does a sendmsg() on the session socket. L2TP and * PPP headers must be inserted into the user's data. */static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m,			    size_t total_len){	static const unsigned char ppph[2] = { 0xff, 0x03 };	struct sock *sk = sock->sk;	struct inet_sock *inet;	__wsum csum = 0;	struct sk_buff *skb;	int error;	int hdr_len;	struct pppol2tp_session *session;	struct pppol2tp_tunnel *tunnel;	struct udphdr *uh;	unsigned int len;	error = -ENOTCONN;	if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED))		goto error;	/* Get session and tunnel contexts */	error = -EBADF;	session = pppol2tp_sock_to_session(sk);	if (session == NULL)		goto error;	tunnel = pppol2tp_sock_to_tunnel(session->tunnel_sock);	if (tunnel == NULL)		goto error;	/* What header length is configured for this session? */	hdr_len = pppol2tp_l2tp_header_len(session);	/* Allocate a socket buffer */	error = -ENOMEM;	skb = sock_wmalloc(sk, NET_SKB_PAD + sizeof(struct iphdr) +			   sizeof(struct udphdr) + hdr_len +			   sizeof(ppph) + total_len,			   0, GFP_KERNEL);	if (!skb)		goto error;	/* Reserve space for headers. */	skb_reserve(skb, NET_SKB_PAD);	skb_reset_network_header(skb);	skb_reserve(skb, sizeof(struct iphdr));	skb_reset_transport_header(skb);	/* Build UDP header */	inet = inet_sk(session->tunnel_sock);	uh = (struct udphdr *) skb->data;	uh->source = inet->sport;	uh->dest = inet->dport;	uh->len = htons(hdr_len + sizeof(ppph) + total_len);	uh->check = 0;	skb_put(skb, sizeof(struct udphdr));	/* Build L2TP header */	pppol2tp_build_l2tp_header(session, skb->data);	skb_put(skb, hdr_len);	/* Add PPP header */	skb->data[0] = ppph[0];	skb->data[1] = ppph[1];	skb_put(skb, 2);	/* Copy user data into skb */	error = memcpy_fromiovec(skb->data, m->msg_iov, total_len);	if (error < 0) {		kfree_skb(skb);		goto error;	}	skb_put(skb, total_len);	/* Calculate UDP checksum if configured to do so */	if (session->tunnel_sock->sk_no_check != UDP_CSUM_NOXMIT)		csum = udp_csum_outgoing(sk, skb);	/* Debug */	if (session->send_seq)		PRINTK(session->debug, PPPOL2TP_MSG_DATA, KERN_DEBUG,		       "%s: send %Zd bytes, ns=%hu\n", session->name,		       total_len, session->ns - 1);	else		PRINTK(session->debug, PPPOL2TP_MSG_DATA, KERN_DEBUG,		       "%s: send %Zd bytes\n", session->name, total_len);	if (session->debug & PPPOL2TP_MSG_DATA) {		int i;		unsigned char *datap = skb->data;		printk(KERN_DEBUG "%s: xmit:", session->name);		for (i = 0; i < total_len; i++) {			printk(" %02X", *datap++);			if (i == 15) {				printk(" ...");				break;			}		}		printk("\n");	}	/* Queue the packet to IP for output */	len = skb->len;	error = ip_queue_xmit(skb, 1);	/* Update stats */	if (error >= 0) {		tunnel->stats.tx_packets++;		tunnel->stats.tx_bytes += len;		session->stats.tx_packets++;		session->stats.tx_bytes += len;	} else {		tunnel->stats.tx_errors++;		session->stats.tx_errors++;	}error:	return error;}/* Transmit function called by generic PPP driver.  Sends PPP frame * over PPPoL2TP socket. * * This is almost the same as pppol2tp_sendmsg(), but rather than * being called with a msghdr from userspace, it is called with a skb * from the kernel. * * The supplied skb from ppp doesn't have enough headroom for the * insertion of L2TP, UDP and IP headers so we need to allocate more * headroom in the skb. This will create a cloned skb. But we must be * careful in the error case because the caller will expect to free * the skb it supplied, not our cloned skb. So we take care to always * leave the original skb unfreed if we return an error. */static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb){	static const u8 ppph[2] = { 0xff, 0x03 };	struct sock *sk = (struct sock *) chan->private;	struct sock *sk_tun;	int hdr_len;	struct pppol2tp_session *session;	struct pppol2tp_tunnel *tunnel;	int rc;	int headroom;	int data_len = skb->len;	struct inet_sock *inet;	__wsum csum = 0;	struct udphdr *uh;	unsigned int len;	if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED))		goto abort;	/* Get session and tunnel contexts from the socket */	session = pppol2tp_sock_to_session(sk);	if (session == NULL)		goto abort;	sk_tun = session->tunnel_sock;	if (sk_tun == NULL)		goto abort;	tunnel = pppol2tp_sock_to_tunnel(sk_tun);	if (tunnel == NULL)

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?