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 u8 mux_id; 27 int r; 28 29 mux_id = RMNET_MAP_GET_MUX_ID(skb); 30 cmd = RMNET_MAP_GET_CMD_START(skb); 31 32 if (mux_id >= RMNET_MAX_LOGICAL_EP) { 33 kfree_skb(skb); 34 return RX_HANDLER_CONSUMED; 35 } 36 37 ep = rmnet_get_endpoint(port, mux_id); 38 if (!ep) { 39 kfree_skb(skb); 40 return RX_HANDLER_CONSUMED; 41 } 42 43 vnd = ep->egress_dev; 44 45 /* Ignore the ip family and pass the sequence number for both v4 and v6 46 * sequence. User space does not support creating dedicated flows for 47 * the 2 protocols 48 */ 49 r = rmnet_vnd_do_flow_control(vnd, enable); 50 if (r) { 51 kfree_skb(skb); 52 return RMNET_MAP_COMMAND_UNSUPPORTED; 53 } else { 54 return RMNET_MAP_COMMAND_ACK; 55 } 56 } 57 58 static void rmnet_map_send_ack(struct sk_buff *skb, 59 unsigned char type, 60 struct rmnet_port *port) 61 { 62 struct rmnet_map_control_command *cmd; 63 struct net_device *dev = skb->dev; 64 65 if (port->data_format & RMNET_FLAGS_INGRESS_MAP_CKSUMV4) 66 skb_trim(skb, 67 skb->len - sizeof(struct rmnet_map_dl_csum_trailer)); 68 69 skb->protocol = htons(ETH_P_MAP); 70 71 cmd = RMNET_MAP_GET_CMD_START(skb); 72 cmd->cmd_type = type & 0x03; 73 74 netif_tx_lock(dev); 75 dev->netdev_ops->ndo_start_xmit(skb, dev); 76 netif_tx_unlock(dev); 77 } 78 79 /* Process MAP command frame and send N/ACK message as appropriate. Message cmd 80 * name is decoded here and appropriate handler is called. 81 */ 82 void rmnet_map_command(struct sk_buff *skb, struct rmnet_port *port) 83 { 84 struct rmnet_map_control_command *cmd; 85 unsigned char command_name; 86 unsigned char rc = 0; 87 88 cmd = RMNET_MAP_GET_CMD_START(skb); 89 command_name = cmd->command_name; 90 91 switch (command_name) { 92 case RMNET_MAP_COMMAND_FLOW_ENABLE: 93 rc = rmnet_map_do_flow_control(skb, port, 1); 94 break; 95 96 case RMNET_MAP_COMMAND_FLOW_DISABLE: 97 rc = rmnet_map_do_flow_control(skb, port, 0); 98 break; 99 100 default: 101 rc = RMNET_MAP_COMMAND_UNSUPPORTED; 102 kfree_skb(skb); 103 break; 104 } 105 if (rc == RMNET_MAP_COMMAND_ACK) 106 rmnet_map_send_ack(skb, rc, port); 107 } 108