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

Commit 3f23e2d4 authored by Chris Lew's avatar Chris Lew
Browse files

net: qrtr: Attempt to linearize skb for forwarding



The current QRTR transport feature set does not support fragmented skbs
which is a problem for packets that are forwarded from the rx path.

In order to linearize the skb, skb_put_padto() and skb_linearize() try
to allocate enough memory with GFP_ATOMIC but are prone to failure.

Pre-allocate enough headeroom with GFP_KERNEL on forwarded packets. If
there are still problems with allocation, then continue and drop the
packet in qrtr_node_enqueue().

Change-Id: I7de6620bba26746698237d913ce064ea5725f921
Signed-off-by: default avatarChris Lew <clew@codeaurora.org>
parent 29ba5ffa
Loading
Loading
Loading
Loading
+20 −0
Original line number Diff line number Diff line
@@ -808,6 +808,24 @@ static struct sk_buff *qrtr_alloc_ctrl_packet(struct qrtr_ctrl_pkt **pkt)
static struct qrtr_sock *qrtr_port_lookup(int port);
static void qrtr_port_put(struct qrtr_sock *ipc);

/* Prepare skb for forwarding by allocating enough linear memory to align and
 * add the header since qrtr transports do not support fragmented skbs
 */
static void qrtr_skb_align_linearize(struct sk_buff *skb)
{
	int nhead = ALIGN(skb->len, 4) + sizeof(struct qrtr_hdr_v1);
	int rc;

	if (!skb_is_nonlinear(skb))
		return;

	rc = pskb_expand_head(skb, nhead, 0, GFP_KERNEL);
	skb_condense(skb);
	if (rc)
		pr_err("%s: failed:%d to allocate linear skb size:%d\n",
		       __func__, rc, nhead);
}

static bool qrtr_must_forward(struct qrtr_node *src,
			      struct qrtr_node *dst, u32 type)
{
@@ -838,6 +856,7 @@ static void qrtr_fwd_ctrl_pkt(struct sk_buff *skb)
	struct qrtr_node *src;
	struct qrtr_cb *cb = (struct qrtr_cb *)skb->cb;

	qrtr_skb_align_linearize(skb);
	src = qrtr_node_lookup(cb->src_node);
	down_read(&qrtr_node_lock);
	list_for_each_entry(node, &qrtr_all_epts, item) {
@@ -872,6 +891,7 @@ static void qrtr_fwd_pkt(struct sk_buff *skb, struct qrtr_cb *cb)
	struct sockaddr_qrtr to = {AF_QIPCRTR, cb->dst_node, cb->dst_port};
	struct qrtr_node *node;

	qrtr_skb_align_linearize(skb);
	node = qrtr_node_lookup(cb->dst_node);
	if (!node)
		return;