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