1 /* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
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.
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.
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"
19 static u8
rmnet_map_do_flow_control(struct sk_buff
*skb
,
20 struct rmnet_port
*port
,
23 struct rmnet_map_control_command
*cmd
;
24 struct rmnet_endpoint
*ep
;
25 struct net_device
*vnd
;
32 mux_id
= RMNET_MAP_GET_MUX_ID(skb
);
33 cmd
= RMNET_MAP_GET_CMD_START(skb
);
35 if (mux_id
>= RMNET_MAX_LOGICAL_EP
) {
37 return RX_HANDLER_CONSUMED
;
40 ep
= rmnet_get_endpoint(port
, mux_id
);
43 return RX_HANDLER_CONSUMED
;
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
);
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
56 r
= rmnet_vnd_do_flow_control(vnd
, enable
);
59 return RMNET_MAP_COMMAND_UNSUPPORTED
;
61 return RMNET_MAP_COMMAND_ACK
;
65 static void rmnet_map_send_ack(struct sk_buff
*skb
,
67 struct rmnet_port
*port
)
69 struct rmnet_map_control_command
*cmd
;
72 if (port
->data_format
& RMNET_INGRESS_FORMAT_MAP_CKSUMV4
) {
73 if (skb
->len
< sizeof(struct rmnet_map_header
) +
74 RMNET_MAP_GET_LENGTH(skb
) +
75 sizeof(struct rmnet_map_dl_csum_trailer
)) {
80 skb_trim(skb
, skb
->len
-
81 sizeof(struct rmnet_map_dl_csum_trailer
));
84 skb
->protocol
= htons(ETH_P_MAP
);
86 cmd
= RMNET_MAP_GET_CMD_START(skb
);
87 cmd
->cmd_type
= type
& 0x03;
89 netif_tx_lock(skb
->dev
);
90 xmit_status
= skb
->dev
->netdev_ops
->ndo_start_xmit(skb
, skb
->dev
);
91 netif_tx_unlock(skb
->dev
);
94 /* Process MAP command frame and send N/ACK message as appropriate. Message cmd
95 * name is decoded here and appropriate handler is called.
97 void rmnet_map_command(struct sk_buff
*skb
, struct rmnet_port
*port
)
99 struct rmnet_map_control_command
*cmd
;
100 unsigned char command_name
;
101 unsigned char rc
= 0;
103 cmd
= RMNET_MAP_GET_CMD_START(skb
);
104 command_name
= cmd
->command_name
;
106 switch (command_name
) {
107 case RMNET_MAP_COMMAND_FLOW_ENABLE
:
108 rc
= rmnet_map_do_flow_control(skb
, port
, 1);
111 case RMNET_MAP_COMMAND_FLOW_DISABLE
:
112 rc
= rmnet_map_do_flow_control(skb
, port
, 0);
116 rc
= RMNET_MAP_COMMAND_UNSUPPORTED
;
120 if (rc
== RMNET_MAP_COMMAND_ACK
)
121 rmnet_map_send_ack(skb
, rc
, port
);