From 7f745d03793df766a5c988463368a3cdafd2121e Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Mon, 14 Oct 2019 17:19:45 -0700 Subject: [PATCH] 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 headroom 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: Chris Lew --- net/qrtr/qrtr.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/net/qrtr/qrtr.c b/net/qrtr/qrtr.c index c6f4cd3aa187..8f286afee4f5 100644 --- a/net/qrtr/qrtr.c +++ b/net/qrtr/qrtr.c @@ -819,6 +819,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) { @@ -849,6 +867,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) { @@ -883,6 +902,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) { kfree_skb(skb);