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