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 11 static 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 48 static 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 */ 72 void 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