1 /* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. 2 * 3 * This program is free software; you can redistribute it and/or modify 4 * it under the terms of the GNU General Public License version 2 and 5 * only version 2 as published by the Free Software Foundation. 6 * 7 * This program is distributed in the hope that it will be useful, 8 * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 * GNU General Public License for more details. 11 */ 12 13 #include <linux/netdevice.h> 14 #include "rmnet_config.h" 15 #include "rmnet_map.h" 16 #include "rmnet_private.h" 17 #include "rmnet_vnd.h" 18 19 static u8 rmnet_map_do_flow_control(struct sk_buff *skb, 20 struct rmnet_port *port, 21 int enable) 22 { 23 struct rmnet_map_control_command *cmd; 24 struct rmnet_endpoint *ep; 25 struct net_device *vnd; 26 u16 ip_family; 27 u16 fc_seq; 28 u32 qos_id; 29 u8 mux_id; 30 int r; 31 32 mux_id = RMNET_MAP_GET_MUX_ID(skb); 33 cmd = RMNET_MAP_GET_CMD_START(skb); 34 35 if (mux_id >= RMNET_MAX_LOGICAL_EP) { 36 kfree_skb(skb); 37 return RX_HANDLER_CONSUMED; 38 } 39 40 ep = rmnet_get_endpoint(port, mux_id); 41 if (!ep) { 42 kfree_skb(skb); 43 return RX_HANDLER_CONSUMED; 44 } 45 46 vnd = ep->egress_dev; 47 48 ip_family = cmd->flow_control.ip_family; 49 fc_seq = ntohs(cmd->flow_control.flow_control_seq_num); 50 qos_id = ntohl(cmd->flow_control.qos_id); 51 52 /* Ignore the ip family and pass the sequence number for both v4 and v6 53 * sequence. User space does not support creating dedicated flows for 54 * the 2 protocols 55 */ 56 r = rmnet_vnd_do_flow_control(vnd, enable); 57 if (r) { 58 kfree_skb(skb); 59 return RMNET_MAP_COMMAND_UNSUPPORTED; 60 } else { 61 return RMNET_MAP_COMMAND_ACK; 62 } 63 } 64 65 static void rmnet_map_send_ack(struct sk_buff *skb, 66 unsigned char type, 67 struct rmnet_port *port) 68 { 69 struct rmnet_map_control_command *cmd; 70 struct net_device *dev = skb->dev; 71 72 if (port->data_format & RMNET_FLAGS_INGRESS_MAP_CKSUMV4) 73 skb_trim(skb, 74 skb->len - sizeof(struct rmnet_map_dl_csum_trailer)); 75 76 skb->protocol = htons(ETH_P_MAP); 77 78 cmd = RMNET_MAP_GET_CMD_START(skb); 79 cmd->cmd_type = type & 0x03; 80 81 netif_tx_lock(dev); 82 dev->netdev_ops->ndo_start_xmit(skb, dev); 83 netif_tx_unlock(dev); 84 } 85 86 /* Process MAP command frame and send N/ACK message as appropriate. Message cmd 87 * name is decoded here and appropriate handler is called. 88 */ 89 void rmnet_map_command(struct sk_buff *skb, struct rmnet_port *port) 90 { 91 struct rmnet_map_control_command *cmd; 92 unsigned char command_name; 93 unsigned char rc = 0; 94 95 cmd = RMNET_MAP_GET_CMD_START(skb); 96 command_name = cmd->command_name; 97 98 switch (command_name) { 99 case RMNET_MAP_COMMAND_FLOW_ENABLE: 100 rc = rmnet_map_do_flow_control(skb, port, 1); 101 break; 102 103 case RMNET_MAP_COMMAND_FLOW_DISABLE: 104 rc = rmnet_map_do_flow_control(skb, port, 0); 105 break; 106 107 default: 108 rc = RMNET_MAP_COMMAND_UNSUPPORTED; 109 kfree_skb(skb); 110 break; 111 } 112 if (rc == RMNET_MAP_COMMAND_ACK) 113 rmnet_map_send_ack(skb, rc, port); 114 } 115