From 8648df62f7a7be004b8937236af1d088eb625fd8 Mon Sep 17 00:00:00 2001 From: Vijay Pamidipati Date: Tue, 7 Mar 2017 21:06:04 +0530 Subject: [PATCH] qcacmn: Add new get_tso_num_seg API with address range check Add new get_tso_num_seg API with specific address range checks needed for QCA8074 emulation platform. Change-Id: I00dcfa51cd8bf8b6167c68a18a2c0a1aa7661679 CRs-Fixed: 2004658 --- qdf/linux/src/qdf_nbuf.c | 64 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/qdf/linux/src/qdf_nbuf.c b/qdf/linux/src/qdf_nbuf.c index 7e0b06004331..d6ae4a3d82a4 100644 --- a/qdf/linux/src/qdf_nbuf.c +++ b/qdf/linux/src/qdf_nbuf.c @@ -1691,6 +1691,7 @@ void __qdf_dmaaddr_to_32s(qdf_dma_addr_t dmaaddr, *hi = 0; } } +EXPORT_SYMBOL(__qdf_dmaaddr_to_32s); /** * __qdf_nbuf_fill_tso_cmn_seg_info() - Init function for each TSO nbuf segment @@ -1805,6 +1806,13 @@ uint32_t __qdf_nbuf_get_tso_info(qdf_device_t osdev, struct sk_buff *skb, tso_frag_vaddr = skb->data + tso_cmn_info.eit_hdr_len; /* get the length of the next tso fragment */ tso_frag_len = min(skb_frag_len, tso_seg_size); + + if (tso_frag_len == 0) { + qdf_print("ERROR:tso_frag_len=0, gso_size=%d!!!", + tso_seg_size); + return 0; + } + tso_frag_paddr = dma_map_single(osdev->dev, tso_frag_vaddr, tso_frag_len, DMA_TO_DEVICE); TSO_DEBUG("%s[%d] skb frag len %d tso frag len %d\n", __func__, @@ -1828,6 +1836,7 @@ uint32_t __qdf_nbuf_get_tso_info(qdf_device_t osdev, struct sk_buff *skb, return tso_info->num_segs; curr_seg->seg.tso_flags.ip_len = tso_cmn_info.ip_tcp_hdr_len; + curr_seg->seg.tso_flags.l2_len = tso_cmn_info.l2_len; curr_seg->seg.num_frags++; while (more_tso_frags) { @@ -1984,6 +1993,7 @@ EXPORT_SYMBOL(__qdf_nbuf_unmap_tso_segment); * * Return: 0 - success, 1 - failure */ +#ifndef BUILD_X86 uint32_t __qdf_nbuf_get_tso_num_seg(struct sk_buff *skb) { uint32_t gso_size, tmp_len, num_segs = 0; @@ -1998,8 +2008,62 @@ uint32_t __qdf_nbuf_get_tso_num_seg(struct sk_buff *skb) else break; } + return num_segs; } +#else +uint32_t __qdf_nbuf_get_tso_num_seg(struct sk_buff *skb) +{ + uint32_t i, gso_size, tmp_len, num_segs = 0; + struct skb_frag_struct *frag = NULL; + + /* + * Check if the head SKB or any of frags are allocated in < 0x50000000 + * region which cannot be accessed by Target + */ + if (virt_to_phys(skb->data) < 0x50000040) { + TSO_DEBUG("%s %d: Invalid Address nr_frags = %d, paddr = %p \n", + __func__, __LINE__, skb_shinfo(skb)->nr_frags, + virt_to_phys(skb->data)); + goto fail; + + } + + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + frag = &skb_shinfo(skb)->frags[i]; + + if (!frag) + goto fail; + + if (virt_to_phys(skb_frag_address_safe(frag)) < 0x50000040) + goto fail; + } + + + gso_size = skb_shinfo(skb)->gso_size; + tmp_len = skb->len - ((skb_transport_header(skb) - skb_mac_header(skb)) + + tcp_hdrlen(skb)); + while (tmp_len) { + num_segs++; + if (tmp_len > gso_size) + tmp_len -= gso_size; + else + break; + } + + return num_segs; + + /* + * Do not free this frame, just do socket level accounting + * so that this is not reused. + */ +fail: + if (skb->sk) + atomic_sub(skb->truesize, &(skb->sk->sk_wmem_alloc)); + + return 0; +} +#endif EXPORT_SYMBOL(__qdf_nbuf_get_tso_num_seg); #endif /* FEATURE_TSO */