Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f74ba31b authored by Sam Protsenko's avatar Sam Protsenko Committed by Alistair Strachan
Browse files

UPSTREAM: ppp: Move PFC decompression to PPP generic layer



Extract "Protocol" field decompression code from transport protocols to
PPP generic layer, where it actually belongs. As a consequence, this
patch fixes incorrect place of PFC decompression in L2TP driver (when
it's not PPPOX_BOUND) and also enables this decompression for other
protocols, like PPPoE.

Protocol field decompression also happens in PPP Multilink Protocol
code and in PPP compression protocols implementations (bsd, deflate,
mppe). It looks like there is no easy way to get rid of that, so it was
decided to leave it as is, but provide those cases with appropriate
comments instead.

Changes in v2:
  - Fix the order of checking skb data room and proto decompression
  - Remove "inline" keyword from ppp_decompress_proto()
  - Don't split line before function name
  - Prefix ppp_decompress_proto() function with "__"
  - Add ppp_decompress_proto() function with skb data room checks
  - Add description for introduced functions
  - Fix comments (as per review on mailing list)

Signed-off-by: default avatarSam Protsenko <semen.protsenko@linaro.org>
Reviewed-by: default avatarGuillaume Nault <g.nault@alphalink.fr>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>

(cherry picked from commit 7fb1b8ca8fa1ee34ffc328f17f78da68c7cc04e6)
Bug: 116424816
Signed-off-by: default avatarSam Protsenko <semen.protsenko@linaro.org>
Change-Id: I711d2e9c23949eda459ed42e1ffb5a560aa08bf4
parent 8d03e452
Loading
Loading
Loading
Loading
+7 −7
Original line number Diff line number Diff line
@@ -770,7 +770,7 @@ process_input_packet(struct asyncppp *ap)
{
	struct sk_buff *skb;
	unsigned char *p;
	unsigned int len, fcs, proto;
	unsigned int len, fcs;

	skb = ap->rpkt;
	if (ap->state & (SC_TOSS | SC_ESCAPE))
@@ -799,14 +799,14 @@ process_input_packet(struct asyncppp *ap)
			goto err;
		p = skb_pull(skb, 2);
	}
	proto = p[0];
	if (proto & 1) {
		/* protocol is compressed */
		skb_push(skb, 1)[0] = 0;
	} else {

	/* If protocol field is not compressed, it can be LCP packet */
	if (!(p[0] & 0x01)) {
		unsigned int proto;

		if (skb->len < 2)
			goto err;
		proto = (proto << 8) + p[1];
		proto = (p[0] << 8) + p[1];
		if (proto == PPP_LCP)
			async_lcp_peek(ap, p, skb->len, 1);
	}
+51 −3
Original line number Diff line number Diff line
@@ -1978,6 +1978,46 @@ ppp_do_recv(struct ppp *ppp, struct sk_buff *skb, struct channel *pch)
	ppp_recv_unlock(ppp);
}

/**
 * __ppp_decompress_proto - Decompress protocol field, slim version.
 * @skb: Socket buffer where protocol field should be decompressed. It must have
 *	 at least 1 byte of head room and 1 byte of linear data. First byte of
 *	 data must be a protocol field byte.
 *
 * Decompress protocol field in PPP header if it's compressed, e.g. when
 * Protocol-Field-Compression (PFC) was negotiated. No checks w.r.t. skb data
 * length are done in this function.
 */
static void __ppp_decompress_proto(struct sk_buff *skb)
{
	if (skb->data[0] & 0x01)
		*(u8 *)skb_push(skb, 1) = 0x00;
}

/**
 * ppp_decompress_proto - Check skb data room and decompress protocol field.
 * @skb: Socket buffer where protocol field should be decompressed. First byte
 *	 of data must be a protocol field byte.
 *
 * Decompress protocol field in PPP header if it's compressed, e.g. when
 * Protocol-Field-Compression (PFC) was negotiated. This function also makes
 * sure that skb data room is sufficient for Protocol field, before and after
 * decompression.
 *
 * Return: true - decompressed successfully, false - not enough room in skb.
 */
static bool ppp_decompress_proto(struct sk_buff *skb)
{
	/* At least one byte should be present (if protocol is compressed) */
	if (!pskb_may_pull(skb, 1))
		return false;

	__ppp_decompress_proto(skb);

	/* Protocol field should occupy 2 bytes when not compressed */
	return pskb_may_pull(skb, 2);
}

void
ppp_input(struct ppp_channel *chan, struct sk_buff *skb)
{
@@ -1990,7 +2030,7 @@ ppp_input(struct ppp_channel *chan, struct sk_buff *skb)
	}

	read_lock_bh(&pch->upl);
	if (!pskb_may_pull(skb, 2)) {
	if (!ppp_decompress_proto(skb)) {
		kfree_skb(skb);
		if (pch->ppp) {
			++pch->ppp->dev->stats.rx_length_errors;
@@ -2087,6 +2127,9 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
	if (ppp->flags & SC_MUST_COMP && ppp->rstate & SC_DC_FERROR)
		goto err;

	/* At this point the "Protocol" field MUST be decompressed, either in
	 * ppp_input(), ppp_decompress_frame() or in ppp_receive_mp_frame().
	 */
	proto = PPP_PROTO(skb);
	switch (proto) {
	case PPP_VJC_COMP:
@@ -2258,6 +2301,9 @@ ppp_decompress_frame(struct ppp *ppp, struct sk_buff *skb)
		skb_put(skb, len);
		skb_pull(skb, 2);	/* pull off the A/C bytes */

		/* Don't call __ppp_decompress_proto() here, but instead rely on
		 * corresponding algo (mppe/bsd/deflate) to decompress it.
		 */
	} else {
		/* Uncompressed frame - pass to decompressor so it
		   can update its dictionary if necessary. */
@@ -2303,9 +2349,11 @@ ppp_receive_mp_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch)

	/*
	 * Do protocol ID decompression on the first fragment of each packet.
	 * We have to do that here, because ppp_receive_nonmp_frame() expects
	 * decompressed protocol field.
	 */
	if ((PPP_MP_CB(skb)->BEbits & B) && (skb->data[0] & 1))
		*skb_push(skb, 1) = 0;
	if (PPP_MP_CB(skb)->BEbits & B)
		__ppp_decompress_proto(skb);

	/*
	 * Expand sequence number to 32 bits, making it as close
+4 −5
Original line number Diff line number Diff line
@@ -709,11 +709,10 @@ ppp_sync_input(struct syncppp *ap, const unsigned char *buf,
		p = skb_pull(skb, 2);
	}

	/* decompress protocol field if compressed */
	if (p[0] & 1) {
		/* protocol is compressed */
		skb_push(skb, 1)[0] = 0;
	} else if (skb->len < 2)
	/* PPP packet length should be >= 2 bytes when protocol field is not
	 * compressed.
	 */
	if (!(p[0] & 0x01) && skb->len < 2)
		goto err;

	/* queue the frame to be processed */
+0 −5
Original line number Diff line number Diff line
@@ -326,11 +326,6 @@ static int pptp_rcv_core(struct sock *sk, struct sk_buff *skb)
			skb_pull(skb, 2);
		}

		if ((*skb->data) & 1) {
			/* protocol is compressed */
			skb_push(skb, 1)[0] = 0;
		}

		skb->ip_summed = CHECKSUM_NONE;
		skb_set_network_header(skb, skb->head-skb->data);
		ppp_input(&po->chan, skb);
+0 −4
Original line number Diff line number Diff line
@@ -220,10 +220,6 @@ static void pppol2tp_recv(struct l2tp_session *session, struct sk_buff *skb, int
	    skb->data[1] == PPP_UI)
		skb_pull(skb, 2);

	/* Decompress protocol field if PFC is enabled */
	if ((*skb->data) & 0x1)
		*(u8 *)skb_push(skb, 1) = 0;

	if (sk->sk_state & PPPOX_BOUND) {
		struct pppox_sock *po;