diff options
Diffstat (limited to 'drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c')
-rw-r--r-- | drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c | 70 |
1 files changed, 40 insertions, 30 deletions
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c index 08e4afc0ab39..601edec28c5f 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c @@ -15,6 +15,8 @@ #include <linux/netdevice.h> #include <linux/netdev_features.h> +#include <linux/if_arp.h> +#include <net/sock.h> #include "rmnet_private.h" #include "rmnet_config.h" #include "rmnet_vnd.h" @@ -64,19 +66,19 @@ __rmnet_map_ingress_handler(struct sk_buff *skb, struct rmnet_port *port) { struct rmnet_endpoint *ep; + u16 len, pad; u8 mux_id; - u16 len; if (RMNET_MAP_GET_CD_BIT(skb)) { - if (port->ingress_data_format - & RMNET_INGRESS_FORMAT_MAP_COMMANDS) + if (port->data_format & RMNET_INGRESS_FORMAT_MAP_COMMANDS) return rmnet_map_command(skb, port); goto free_skb; } mux_id = RMNET_MAP_GET_MUX_ID(skb); - len = RMNET_MAP_GET_LENGTH(skb) - RMNET_MAP_GET_PAD(skb); + pad = RMNET_MAP_GET_PAD(skb); + len = RMNET_MAP_GET_LENGTH(skb) - pad; if (mux_id >= RMNET_MAX_LOGICAL_EP) goto free_skb; @@ -89,8 +91,14 @@ __rmnet_map_ingress_handler(struct sk_buff *skb, /* Subtract MAP header */ skb_pull(skb, sizeof(struct rmnet_map_header)); - skb_trim(skb, len); rmnet_set_skb_proto(skb); + + if (port->data_format & RMNET_INGRESS_FORMAT_MAP_CKSUMV4) { + if (!rmnet_map_checksum_downlink_packet(skb, len + pad)) + skb->ip_summed = CHECKSUM_UNNECESSARY; + } + + skb_trim(skb, len); rmnet_deliver_skb(skb); return; @@ -104,8 +112,17 @@ rmnet_map_ingress_handler(struct sk_buff *skb, { struct sk_buff *skbn; - if (port->ingress_data_format & RMNET_INGRESS_FORMAT_DEAGGREGATION) { - while ((skbn = rmnet_map_deaggregate(skb)) != NULL) + if (skb->dev->type == ARPHRD_ETHER) { + if (pskb_expand_head(skb, ETH_HLEN, 0, GFP_KERNEL)) { + kfree_skb(skb); + return; + } + + skb_push(skb, ETH_HLEN); + } + + if (port->data_format & RMNET_INGRESS_FORMAT_DEAGGREGATION) { + while ((skbn = rmnet_map_deaggregate(skb, port)) != NULL) __rmnet_map_ingress_handler(skbn, port); consume_skb(skb); @@ -124,29 +141,32 @@ static int rmnet_map_egress_handler(struct sk_buff *skb, additional_header_len = 0; required_headroom = sizeof(struct rmnet_map_header); + if (port->data_format & RMNET_EGRESS_FORMAT_MAP_CKSUMV4) { + additional_header_len = sizeof(struct rmnet_map_ul_csum_header); + required_headroom += additional_header_len; + } + if (skb_headroom(skb) < required_headroom) { if (pskb_expand_head(skb, required_headroom, 0, GFP_KERNEL)) goto fail; } + if (port->data_format & RMNET_EGRESS_FORMAT_MAP_CKSUMV4) + rmnet_map_checksum_uplink_packet(skb, orig_dev); + map_header = rmnet_map_add_map_header(skb, additional_header_len, 0); if (!map_header) goto fail; - if (port->egress_data_format & RMNET_EGRESS_FORMAT_MUXING) { - if (mux_id == 0xff) - map_header->mux_id = 0; - else - map_header->mux_id = mux_id; - } + map_header->mux_id = mux_id; skb->protocol = htons(ETH_P_MAP); - return RMNET_MAP_SUCCESS; + return 0; fail: kfree_skb(skb); - return RMNET_MAP_CONSUMED; + return -ENOMEM; } static void @@ -178,8 +198,7 @@ rx_handler_result_t rmnet_rx_handler(struct sk_buff **pskb) switch (port->rmnet_mode) { case RMNET_EPMODE_VND: - if (port->ingress_data_format & RMNET_INGRESS_FORMAT_MAP) - rmnet_map_ingress_handler(skb, port); + rmnet_map_ingress_handler(skb, port); break; case RMNET_EPMODE_BRIDGE: rmnet_bridge_handler(skb, port->bridge_ep); @@ -201,6 +220,8 @@ void rmnet_egress_handler(struct sk_buff *skb) struct rmnet_priv *priv; u8 mux_id; + sk_pacing_shift_update(skb->sk, 8); + orig_dev = skb->dev; priv = netdev_priv(orig_dev); skb->dev = priv->real_dev; @@ -212,19 +233,8 @@ void rmnet_egress_handler(struct sk_buff *skb) return; } - if (port->egress_data_format & RMNET_EGRESS_FORMAT_MAP) { - switch (rmnet_map_egress_handler(skb, port, mux_id, orig_dev)) { - case RMNET_MAP_CONSUMED: - return; - - case RMNET_MAP_SUCCESS: - break; - - default: - kfree_skb(skb); - return; - } - } + if (rmnet_map_egress_handler(skb, port, mux_id, orig_dev)) + return; rmnet_vnd_tx_fixup(skb, orig_dev); |