linux/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_command.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
   3 */
   4
   5#include <linux/netdevice.h>
   6#include "rmnet_config.h"
   7#include "rmnet_map.h"
   8#include "rmnet_private.h"
   9#include "rmnet_vnd.h"
  10
  11static u8 rmnet_map_do_flow_control(struct sk_buff *skb,
  12                                    struct rmnet_port *port,
  13                                    int enable)
  14{
  15        struct rmnet_endpoint *ep;
  16        struct net_device *vnd;
  17        u8 mux_id;
  18        int r;
  19
  20        mux_id = RMNET_MAP_GET_MUX_ID(skb);
  21
  22        if (mux_id >= RMNET_MAX_LOGICAL_EP) {
  23                kfree_skb(skb);
  24                return RX_HANDLER_CONSUMED;
  25        }
  26
  27        ep = rmnet_get_endpoint(port, mux_id);
  28        if (!ep) {
  29                kfree_skb(skb);
  30                return RX_HANDLER_CONSUMED;
  31        }
  32
  33        vnd = ep->egress_dev;
  34
  35        /* Ignore the ip family and pass the sequence number for both v4 and v6
  36         * sequence. User space does not support creating dedicated flows for
  37         * the 2 protocols
  38         */
  39        r = rmnet_vnd_do_flow_control(vnd, enable);
  40        if (r) {
  41                kfree_skb(skb);
  42                return RMNET_MAP_COMMAND_UNSUPPORTED;
  43        } else {
  44                return RMNET_MAP_COMMAND_ACK;
  45        }
  46}
  47
  48static void rmnet_map_send_ack(struct sk_buff *skb,
  49                               unsigned char type,
  50                               struct rmnet_port *port)
  51{
  52        struct rmnet_map_control_command *cmd;
  53        struct net_device *dev = skb->dev;
  54
  55        if (port->data_format & RMNET_FLAGS_INGRESS_MAP_CKSUMV4)
  56                skb_trim(skb,
  57                         skb->len - sizeof(struct rmnet_map_dl_csum_trailer));
  58
  59        skb->protocol = htons(ETH_P_MAP);
  60
  61        cmd = RMNET_MAP_GET_CMD_START(skb);
  62        cmd->cmd_type = type & 0x03;
  63
  64        netif_tx_lock(dev);
  65        dev->netdev_ops->ndo_start_xmit(skb, dev);
  66        netif_tx_unlock(dev);
  67}
  68
  69/* Process MAP command frame and send N/ACK message as appropriate. Message cmd
  70 * name is decoded here and appropriate handler is called.
  71 */
  72void rmnet_map_command(struct sk_buff *skb, struct rmnet_port *port)
  73{
  74        struct rmnet_map_control_command *cmd;
  75        unsigned char command_name;
  76        unsigned char rc = 0;
  77
  78        cmd = RMNET_MAP_GET_CMD_START(skb);
  79        command_name = cmd->command_name;
  80
  81        switch (command_name) {
  82        case RMNET_MAP_COMMAND_FLOW_ENABLE:
  83                rc = rmnet_map_do_flow_control(skb, port, 1);
  84                break;
  85
  86        case RMNET_MAP_COMMAND_FLOW_DISABLE:
  87                rc = rmnet_map_do_flow_control(skb, port, 0);
  88                break;
  89
  90        default:
  91                rc = RMNET_MAP_COMMAND_UNSUPPORTED;
  92                kfree_skb(skb);
  93                break;
  94        }
  95        if (rc == RMNET_MAP_COMMAND_ACK)
  96                rmnet_map_send_ack(skb, rc, port);
  97}
  98