Add support for handling the MAP packets as a list in preparation for the subsequent patch in the series which adds support for handling the coalescing packets. This is needed as a single coalescing MAP packet could yield multiple IP packets. There is no functional change in the handling of the previously supported MAP packet formats. Co-developed-by: Sean Tranchetti Signed-off-by: Sean Tranchetti Signed-off-by: Subash Abhinov Kasiviswanathan --- .../ethernet/qualcomm/rmnet/rmnet_handlers.c | 22 +++++-- .../net/ethernet/qualcomm/rmnet/rmnet_map.h | 4 +- .../ethernet/qualcomm/rmnet/rmnet_map_data.c | 57 ++++++++++++------- 3 files changed, 58 insertions(+), 25 deletions(-) diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c index aa5523f4618e..ab1dfbd833e3 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c @@ -50,6 +50,16 @@ rmnet_deliver_skb(struct sk_buff *skb) gro_cells_receive(&priv->gro_cells, skb); } +static void rmnet_deliver_skb_list(struct sk_buff_head *head) +{ + struct sk_buff *skb; + + while ((skb = __skb_dequeue(head))) { + rmnet_set_skb_proto(skb); + rmnet_deliver_skb(skb); + } +} + /* MAP handler */ static void @@ -59,6 +69,7 @@ __rmnet_map_ingress_handler(struct sk_buff *skb, { struct rmnet_map_header *map_header = (void *)skb->data; struct rmnet_endpoint *ep; + struct sk_buff_head list; u16 len, pad; u8 mux_id; @@ -83,12 +94,12 @@ __rmnet_map_ingress_handler(struct sk_buff *skb, skb->dev = ep->egress_dev; + __skb_queue_head_init(&list); + if ((data_format & RMNET_FLAGS_INGRESS_MAP_CKSUMV5) && (map_header->flags & MAP_NEXT_HEADER_FLAG)) { - if (rmnet_map_process_next_hdr_packet(skb, len)) + if (rmnet_map_process_next_hdr_packet(skb, &list, len)) goto free_skb; - skb_pull(skb, sizeof(*map_header)); - rmnet_set_skb_proto(skb); } else { /* Subtract MAP header */ skb_pull(skb, sizeof(*map_header)); @@ -96,10 +107,11 @@ __rmnet_map_ingress_handler(struct sk_buff *skb, if (data_format & RMNET_FLAGS_INGRESS_MAP_CKSUMV4 && !rmnet_map_checksum_downlink_packet(skb, len + pad)) skb->ip_summed = CHECKSUM_UNNECESSARY; + skb_trim(skb, len); + __skb_queue_tail(&list, skb); } - skb_trim(skb, len); - rmnet_deliver_skb(skb); + rmnet_deliver_skb_list(&list); return; free_skb: diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h index 0977e495f591..ef738ce015d4 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h @@ -53,7 +53,9 @@ void rmnet_map_checksum_uplink_packet(struct sk_buff *skb, struct rmnet_port *port, struct net_device *orig_dev, int csum_type); -int rmnet_map_process_next_hdr_packet(struct sk_buff *skb, u16 len); +int rmnet_map_process_next_hdr_packet(struct sk_buff *skb, + struct sk_buff_head *list, + u16 len); unsigned int rmnet_map_tx_aggregate(struct sk_buff *skb, struct rmnet_port *port, struct net_device *orig_dev); void rmnet_map_tx_aggregate_init(struct rmnet_port *port); diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c index 39d6d084e73f..577f2758e385 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c @@ -497,35 +497,54 @@ void rmnet_map_checksum_uplink_packet(struct sk_buff *skb, } } -/* Process a MAPv5 packet header */ +static struct rmnet_map_v5_csum_header * +rmnet_map_get_next_hdr(struct sk_buff *skb) +{ + return (struct rmnet_map_v5_csum_header *)(skb->data + + sizeof(struct rmnet_map_header)); +} + +static u8 rmnet_map_get_next_hdr_type(struct sk_buff *skb) +{ + struct rmnet_map_v5_csum_header *hdr = rmnet_map_get_next_hdr(skb); + + return u8_get_bits(hdr->header_info, MAPV5_HDRINFO_HDR_TYPE_FMASK); +} + +static bool rmnet_map_get_csum_valid(struct sk_buff *skb) +{ + struct rmnet_map_v5_csum_header *hdr = rmnet_map_get_next_hdr(skb); + + return !!(hdr->csum_info & MAPV5_CSUMINFO_VALID_FLAG); +} + int rmnet_map_process_next_hdr_packet(struct sk_buff *skb, + struct sk_buff_head *list, u16 len) { struct rmnet_priv *priv = netdev_priv(skb->dev); - struct rmnet_map_v5_csum_header *next_hdr; - u8 nexthdr_type; - next_hdr = (struct rmnet_map_v5_csum_header *)(skb->data + - sizeof(struct rmnet_map_header)); + switch (rmnet_map_get_next_hdr_type(skb)) { + case RMNET_MAP_HEADER_TYPE_CSUM_OFFLOAD: + if (unlikely(!(skb->dev->features & NETIF_F_RXCSUM))) { + priv->stats.csum_sw++; + } else if (rmnet_map_get_csum_valid(skb)) { + priv->stats.csum_ok++; + skb->ip_summed = CHECKSUM_UNNECESSARY; + } else { + priv->stats.csum_valid_unset++; + } - nexthdr_type = u8_get_bits(next_hdr->header_info, - MAPV5_HDRINFO_HDR_TYPE_FMASK); + skb_pull(skb, sizeof(struct rmnet_map_header) + + sizeof(struct rmnet_map_v5_csum_header)); + skb_trim(skb, len); + __skb_queue_tail(list, skb); + break; - if (nexthdr_type != RMNET_MAP_HEADER_TYPE_CSUM_OFFLOAD) + default: return -EINVAL; - - if (unlikely(!(skb->dev->features & NETIF_F_RXCSUM))) { - priv->stats.csum_sw++; - } else if (next_hdr->csum_info & MAPV5_CSUMINFO_VALID_FLAG) { - priv->stats.csum_ok++; - skb->ip_summed = CHECKSUM_UNNECESSARY; - } else { - priv->stats.csum_valid_unset++; } - /* Pull csum v5 header */ - skb_pull(skb, sizeof(*next_hdr)); - return 0; } -- 2.34.1