1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (C) 2017 - Cambridge Greys Limited
4*4882a593Smuzhiyun * Copyright (C) 2011 - 2014 Cisco Systems Inc
5*4882a593Smuzhiyun */
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun #include <linux/etherdevice.h>
8*4882a593Smuzhiyun #include <linux/netdevice.h>
9*4882a593Smuzhiyun #include <linux/skbuff.h>
10*4882a593Smuzhiyun #include <linux/slab.h>
11*4882a593Smuzhiyun #include <asm/byteorder.h>
12*4882a593Smuzhiyun #include <uapi/linux/ip.h>
13*4882a593Smuzhiyun #include <uapi/linux/virtio_net.h>
14*4882a593Smuzhiyun #include <linux/virtio_net.h>
15*4882a593Smuzhiyun #include <linux/virtio_byteorder.h>
16*4882a593Smuzhiyun #include <linux/netdev_features.h>
17*4882a593Smuzhiyun #include "vector_user.h"
18*4882a593Smuzhiyun #include "vector_kern.h"
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun #define GOOD_LINEAR 512
21*4882a593Smuzhiyun #define GSO_ERROR "Incoming GSO frames and GRO disabled on the interface"
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun struct gre_minimal_header {
24*4882a593Smuzhiyun uint16_t header;
25*4882a593Smuzhiyun uint16_t arptype;
26*4882a593Smuzhiyun };
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun struct uml_gre_data {
30*4882a593Smuzhiyun uint32_t rx_key;
31*4882a593Smuzhiyun uint32_t tx_key;
32*4882a593Smuzhiyun uint32_t sequence;
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun bool ipv6;
35*4882a593Smuzhiyun bool has_sequence;
36*4882a593Smuzhiyun bool pin_sequence;
37*4882a593Smuzhiyun bool checksum;
38*4882a593Smuzhiyun bool key;
39*4882a593Smuzhiyun struct gre_minimal_header expected_header;
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun uint32_t checksum_offset;
42*4882a593Smuzhiyun uint32_t key_offset;
43*4882a593Smuzhiyun uint32_t sequence_offset;
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun };
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun struct uml_l2tpv3_data {
48*4882a593Smuzhiyun uint64_t rx_cookie;
49*4882a593Smuzhiyun uint64_t tx_cookie;
50*4882a593Smuzhiyun uint64_t rx_session;
51*4882a593Smuzhiyun uint64_t tx_session;
52*4882a593Smuzhiyun uint32_t counter;
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun bool udp;
55*4882a593Smuzhiyun bool ipv6;
56*4882a593Smuzhiyun bool has_counter;
57*4882a593Smuzhiyun bool pin_counter;
58*4882a593Smuzhiyun bool cookie;
59*4882a593Smuzhiyun bool cookie_is_64;
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun uint32_t cookie_offset;
62*4882a593Smuzhiyun uint32_t session_offset;
63*4882a593Smuzhiyun uint32_t counter_offset;
64*4882a593Smuzhiyun };
65*4882a593Smuzhiyun
l2tpv3_form_header(uint8_t * header,struct sk_buff * skb,struct vector_private * vp)66*4882a593Smuzhiyun static int l2tpv3_form_header(uint8_t *header,
67*4882a593Smuzhiyun struct sk_buff *skb, struct vector_private *vp)
68*4882a593Smuzhiyun {
69*4882a593Smuzhiyun struct uml_l2tpv3_data *td = vp->transport_data;
70*4882a593Smuzhiyun uint32_t *counter;
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun if (td->udp)
73*4882a593Smuzhiyun *(uint32_t *) header = cpu_to_be32(L2TPV3_DATA_PACKET);
74*4882a593Smuzhiyun (*(uint32_t *) (header + td->session_offset)) = td->tx_session;
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun if (td->cookie) {
77*4882a593Smuzhiyun if (td->cookie_is_64)
78*4882a593Smuzhiyun (*(uint64_t *)(header + td->cookie_offset)) =
79*4882a593Smuzhiyun td->tx_cookie;
80*4882a593Smuzhiyun else
81*4882a593Smuzhiyun (*(uint32_t *)(header + td->cookie_offset)) =
82*4882a593Smuzhiyun td->tx_cookie;
83*4882a593Smuzhiyun }
84*4882a593Smuzhiyun if (td->has_counter) {
85*4882a593Smuzhiyun counter = (uint32_t *)(header + td->counter_offset);
86*4882a593Smuzhiyun if (td->pin_counter) {
87*4882a593Smuzhiyun *counter = 0;
88*4882a593Smuzhiyun } else {
89*4882a593Smuzhiyun td->counter++;
90*4882a593Smuzhiyun *counter = cpu_to_be32(td->counter);
91*4882a593Smuzhiyun }
92*4882a593Smuzhiyun }
93*4882a593Smuzhiyun return 0;
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun
gre_form_header(uint8_t * header,struct sk_buff * skb,struct vector_private * vp)96*4882a593Smuzhiyun static int gre_form_header(uint8_t *header,
97*4882a593Smuzhiyun struct sk_buff *skb, struct vector_private *vp)
98*4882a593Smuzhiyun {
99*4882a593Smuzhiyun struct uml_gre_data *td = vp->transport_data;
100*4882a593Smuzhiyun uint32_t *sequence;
101*4882a593Smuzhiyun *((uint32_t *) header) = *((uint32_t *) &td->expected_header);
102*4882a593Smuzhiyun if (td->key)
103*4882a593Smuzhiyun (*(uint32_t *) (header + td->key_offset)) = td->tx_key;
104*4882a593Smuzhiyun if (td->has_sequence) {
105*4882a593Smuzhiyun sequence = (uint32_t *)(header + td->sequence_offset);
106*4882a593Smuzhiyun if (td->pin_sequence)
107*4882a593Smuzhiyun *sequence = 0;
108*4882a593Smuzhiyun else
109*4882a593Smuzhiyun *sequence = cpu_to_be32(++td->sequence);
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun return 0;
112*4882a593Smuzhiyun }
113*4882a593Smuzhiyun
raw_form_header(uint8_t * header,struct sk_buff * skb,struct vector_private * vp)114*4882a593Smuzhiyun static int raw_form_header(uint8_t *header,
115*4882a593Smuzhiyun struct sk_buff *skb, struct vector_private *vp)
116*4882a593Smuzhiyun {
117*4882a593Smuzhiyun struct virtio_net_hdr *vheader = (struct virtio_net_hdr *) header;
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun virtio_net_hdr_from_skb(
120*4882a593Smuzhiyun skb,
121*4882a593Smuzhiyun vheader,
122*4882a593Smuzhiyun virtio_legacy_is_little_endian(),
123*4882a593Smuzhiyun false,
124*4882a593Smuzhiyun 0
125*4882a593Smuzhiyun );
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun return 0;
128*4882a593Smuzhiyun }
129*4882a593Smuzhiyun
l2tpv3_verify_header(uint8_t * header,struct sk_buff * skb,struct vector_private * vp)130*4882a593Smuzhiyun static int l2tpv3_verify_header(
131*4882a593Smuzhiyun uint8_t *header, struct sk_buff *skb, struct vector_private *vp)
132*4882a593Smuzhiyun {
133*4882a593Smuzhiyun struct uml_l2tpv3_data *td = vp->transport_data;
134*4882a593Smuzhiyun uint32_t *session;
135*4882a593Smuzhiyun uint64_t cookie;
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun if ((!td->udp) && (!td->ipv6))
138*4882a593Smuzhiyun header += sizeof(struct iphdr) /* fix for ipv4 raw */;
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun /* we do not do a strict check for "data" packets as per
141*4882a593Smuzhiyun * the RFC spec because the pure IP spec does not have
142*4882a593Smuzhiyun * that anyway.
143*4882a593Smuzhiyun */
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun if (td->cookie) {
146*4882a593Smuzhiyun if (td->cookie_is_64)
147*4882a593Smuzhiyun cookie = *(uint64_t *)(header + td->cookie_offset);
148*4882a593Smuzhiyun else
149*4882a593Smuzhiyun cookie = *(uint32_t *)(header + td->cookie_offset);
150*4882a593Smuzhiyun if (cookie != td->rx_cookie) {
151*4882a593Smuzhiyun if (net_ratelimit())
152*4882a593Smuzhiyun netdev_err(vp->dev, "uml_l2tpv3: unknown cookie id");
153*4882a593Smuzhiyun return -1;
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun }
156*4882a593Smuzhiyun session = (uint32_t *) (header + td->session_offset);
157*4882a593Smuzhiyun if (*session != td->rx_session) {
158*4882a593Smuzhiyun if (net_ratelimit())
159*4882a593Smuzhiyun netdev_err(vp->dev, "uml_l2tpv3: session mismatch");
160*4882a593Smuzhiyun return -1;
161*4882a593Smuzhiyun }
162*4882a593Smuzhiyun return 0;
163*4882a593Smuzhiyun }
164*4882a593Smuzhiyun
gre_verify_header(uint8_t * header,struct sk_buff * skb,struct vector_private * vp)165*4882a593Smuzhiyun static int gre_verify_header(
166*4882a593Smuzhiyun uint8_t *header, struct sk_buff *skb, struct vector_private *vp)
167*4882a593Smuzhiyun {
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun uint32_t key;
170*4882a593Smuzhiyun struct uml_gre_data *td = vp->transport_data;
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun if (!td->ipv6)
173*4882a593Smuzhiyun header += sizeof(struct iphdr) /* fix for ipv4 raw */;
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun if (*((uint32_t *) header) != *((uint32_t *) &td->expected_header)) {
176*4882a593Smuzhiyun if (net_ratelimit())
177*4882a593Smuzhiyun netdev_err(vp->dev, "header type disagreement, expecting %0x, got %0x",
178*4882a593Smuzhiyun *((uint32_t *) &td->expected_header),
179*4882a593Smuzhiyun *((uint32_t *) header)
180*4882a593Smuzhiyun );
181*4882a593Smuzhiyun return -1;
182*4882a593Smuzhiyun }
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun if (td->key) {
185*4882a593Smuzhiyun key = (*(uint32_t *)(header + td->key_offset));
186*4882a593Smuzhiyun if (key != td->rx_key) {
187*4882a593Smuzhiyun if (net_ratelimit())
188*4882a593Smuzhiyun netdev_err(vp->dev, "unknown key id %0x, expecting %0x",
189*4882a593Smuzhiyun key, td->rx_key);
190*4882a593Smuzhiyun return -1;
191*4882a593Smuzhiyun }
192*4882a593Smuzhiyun }
193*4882a593Smuzhiyun return 0;
194*4882a593Smuzhiyun }
195*4882a593Smuzhiyun
raw_verify_header(uint8_t * header,struct sk_buff * skb,struct vector_private * vp)196*4882a593Smuzhiyun static int raw_verify_header(
197*4882a593Smuzhiyun uint8_t *header, struct sk_buff *skb, struct vector_private *vp)
198*4882a593Smuzhiyun {
199*4882a593Smuzhiyun struct virtio_net_hdr *vheader = (struct virtio_net_hdr *) header;
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun if ((vheader->gso_type != VIRTIO_NET_HDR_GSO_NONE) &&
202*4882a593Smuzhiyun (vp->req_size != 65536)) {
203*4882a593Smuzhiyun if (net_ratelimit())
204*4882a593Smuzhiyun netdev_err(
205*4882a593Smuzhiyun vp->dev,
206*4882a593Smuzhiyun GSO_ERROR
207*4882a593Smuzhiyun );
208*4882a593Smuzhiyun }
209*4882a593Smuzhiyun if ((vheader->flags & VIRTIO_NET_HDR_F_DATA_VALID) > 0)
210*4882a593Smuzhiyun return 1;
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun virtio_net_hdr_to_skb(skb, vheader, virtio_legacy_is_little_endian());
213*4882a593Smuzhiyun return 0;
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun
get_uint_param(struct arglist * def,char * param,unsigned int * result)216*4882a593Smuzhiyun static bool get_uint_param(
217*4882a593Smuzhiyun struct arglist *def, char *param, unsigned int *result)
218*4882a593Smuzhiyun {
219*4882a593Smuzhiyun char *arg = uml_vector_fetch_arg(def, param);
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun if (arg != NULL) {
222*4882a593Smuzhiyun if (kstrtoint(arg, 0, result) == 0)
223*4882a593Smuzhiyun return true;
224*4882a593Smuzhiyun }
225*4882a593Smuzhiyun return false;
226*4882a593Smuzhiyun }
227*4882a593Smuzhiyun
get_ulong_param(struct arglist * def,char * param,unsigned long * result)228*4882a593Smuzhiyun static bool get_ulong_param(
229*4882a593Smuzhiyun struct arglist *def, char *param, unsigned long *result)
230*4882a593Smuzhiyun {
231*4882a593Smuzhiyun char *arg = uml_vector_fetch_arg(def, param);
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun if (arg != NULL) {
234*4882a593Smuzhiyun if (kstrtoul(arg, 0, result) == 0)
235*4882a593Smuzhiyun return true;
236*4882a593Smuzhiyun return true;
237*4882a593Smuzhiyun }
238*4882a593Smuzhiyun return false;
239*4882a593Smuzhiyun }
240*4882a593Smuzhiyun
build_gre_transport_data(struct vector_private * vp)241*4882a593Smuzhiyun static int build_gre_transport_data(struct vector_private *vp)
242*4882a593Smuzhiyun {
243*4882a593Smuzhiyun struct uml_gre_data *td;
244*4882a593Smuzhiyun int temp_int;
245*4882a593Smuzhiyun int temp_rx;
246*4882a593Smuzhiyun int temp_tx;
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun vp->transport_data = kmalloc(sizeof(struct uml_gre_data), GFP_KERNEL);
249*4882a593Smuzhiyun if (vp->transport_data == NULL)
250*4882a593Smuzhiyun return -ENOMEM;
251*4882a593Smuzhiyun td = vp->transport_data;
252*4882a593Smuzhiyun td->sequence = 0;
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun td->expected_header.arptype = GRE_IRB;
255*4882a593Smuzhiyun td->expected_header.header = 0;
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun vp->form_header = &gre_form_header;
258*4882a593Smuzhiyun vp->verify_header = &gre_verify_header;
259*4882a593Smuzhiyun vp->header_size = 4;
260*4882a593Smuzhiyun td->key_offset = 4;
261*4882a593Smuzhiyun td->sequence_offset = 4;
262*4882a593Smuzhiyun td->checksum_offset = 4;
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun td->ipv6 = false;
265*4882a593Smuzhiyun if (get_uint_param(vp->parsed, "v6", &temp_int)) {
266*4882a593Smuzhiyun if (temp_int > 0)
267*4882a593Smuzhiyun td->ipv6 = true;
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun td->key = false;
270*4882a593Smuzhiyun if (get_uint_param(vp->parsed, "rx_key", &temp_rx)) {
271*4882a593Smuzhiyun if (get_uint_param(vp->parsed, "tx_key", &temp_tx)) {
272*4882a593Smuzhiyun td->key = true;
273*4882a593Smuzhiyun td->expected_header.header |= GRE_MODE_KEY;
274*4882a593Smuzhiyun td->rx_key = cpu_to_be32(temp_rx);
275*4882a593Smuzhiyun td->tx_key = cpu_to_be32(temp_tx);
276*4882a593Smuzhiyun vp->header_size += 4;
277*4882a593Smuzhiyun td->sequence_offset += 4;
278*4882a593Smuzhiyun } else {
279*4882a593Smuzhiyun return -EINVAL;
280*4882a593Smuzhiyun }
281*4882a593Smuzhiyun }
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun td->sequence = false;
284*4882a593Smuzhiyun if (get_uint_param(vp->parsed, "sequence", &temp_int)) {
285*4882a593Smuzhiyun if (temp_int > 0) {
286*4882a593Smuzhiyun vp->header_size += 4;
287*4882a593Smuzhiyun td->has_sequence = true;
288*4882a593Smuzhiyun td->expected_header.header |= GRE_MODE_SEQUENCE;
289*4882a593Smuzhiyun if (get_uint_param(
290*4882a593Smuzhiyun vp->parsed, "pin_sequence", &temp_int)) {
291*4882a593Smuzhiyun if (temp_int > 0)
292*4882a593Smuzhiyun td->pin_sequence = true;
293*4882a593Smuzhiyun }
294*4882a593Smuzhiyun }
295*4882a593Smuzhiyun }
296*4882a593Smuzhiyun vp->rx_header_size = vp->header_size;
297*4882a593Smuzhiyun if (!td->ipv6)
298*4882a593Smuzhiyun vp->rx_header_size += sizeof(struct iphdr);
299*4882a593Smuzhiyun return 0;
300*4882a593Smuzhiyun }
301*4882a593Smuzhiyun
build_l2tpv3_transport_data(struct vector_private * vp)302*4882a593Smuzhiyun static int build_l2tpv3_transport_data(struct vector_private *vp)
303*4882a593Smuzhiyun {
304*4882a593Smuzhiyun
305*4882a593Smuzhiyun struct uml_l2tpv3_data *td;
306*4882a593Smuzhiyun int temp_int, temp_rxs, temp_txs;
307*4882a593Smuzhiyun unsigned long temp_rx;
308*4882a593Smuzhiyun unsigned long temp_tx;
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun vp->transport_data = kmalloc(
311*4882a593Smuzhiyun sizeof(struct uml_l2tpv3_data), GFP_KERNEL);
312*4882a593Smuzhiyun
313*4882a593Smuzhiyun if (vp->transport_data == NULL)
314*4882a593Smuzhiyun return -ENOMEM;
315*4882a593Smuzhiyun
316*4882a593Smuzhiyun td = vp->transport_data;
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun vp->form_header = &l2tpv3_form_header;
319*4882a593Smuzhiyun vp->verify_header = &l2tpv3_verify_header;
320*4882a593Smuzhiyun td->counter = 0;
321*4882a593Smuzhiyun
322*4882a593Smuzhiyun vp->header_size = 4;
323*4882a593Smuzhiyun td->session_offset = 0;
324*4882a593Smuzhiyun td->cookie_offset = 4;
325*4882a593Smuzhiyun td->counter_offset = 4;
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun
328*4882a593Smuzhiyun td->ipv6 = false;
329*4882a593Smuzhiyun if (get_uint_param(vp->parsed, "v6", &temp_int)) {
330*4882a593Smuzhiyun if (temp_int > 0)
331*4882a593Smuzhiyun td->ipv6 = true;
332*4882a593Smuzhiyun }
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun if (get_uint_param(vp->parsed, "rx_session", &temp_rxs)) {
335*4882a593Smuzhiyun if (get_uint_param(vp->parsed, "tx_session", &temp_txs)) {
336*4882a593Smuzhiyun td->tx_session = cpu_to_be32(temp_txs);
337*4882a593Smuzhiyun td->rx_session = cpu_to_be32(temp_rxs);
338*4882a593Smuzhiyun } else {
339*4882a593Smuzhiyun return -EINVAL;
340*4882a593Smuzhiyun }
341*4882a593Smuzhiyun } else {
342*4882a593Smuzhiyun return -EINVAL;
343*4882a593Smuzhiyun }
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun td->cookie_is_64 = false;
346*4882a593Smuzhiyun if (get_uint_param(vp->parsed, "cookie64", &temp_int)) {
347*4882a593Smuzhiyun if (temp_int > 0)
348*4882a593Smuzhiyun td->cookie_is_64 = true;
349*4882a593Smuzhiyun }
350*4882a593Smuzhiyun td->cookie = false;
351*4882a593Smuzhiyun if (get_ulong_param(vp->parsed, "rx_cookie", &temp_rx)) {
352*4882a593Smuzhiyun if (get_ulong_param(vp->parsed, "tx_cookie", &temp_tx)) {
353*4882a593Smuzhiyun td->cookie = true;
354*4882a593Smuzhiyun if (td->cookie_is_64) {
355*4882a593Smuzhiyun td->rx_cookie = cpu_to_be64(temp_rx);
356*4882a593Smuzhiyun td->tx_cookie = cpu_to_be64(temp_tx);
357*4882a593Smuzhiyun vp->header_size += 8;
358*4882a593Smuzhiyun td->counter_offset += 8;
359*4882a593Smuzhiyun } else {
360*4882a593Smuzhiyun td->rx_cookie = cpu_to_be32(temp_rx);
361*4882a593Smuzhiyun td->tx_cookie = cpu_to_be32(temp_tx);
362*4882a593Smuzhiyun vp->header_size += 4;
363*4882a593Smuzhiyun td->counter_offset += 4;
364*4882a593Smuzhiyun }
365*4882a593Smuzhiyun } else {
366*4882a593Smuzhiyun return -EINVAL;
367*4882a593Smuzhiyun }
368*4882a593Smuzhiyun }
369*4882a593Smuzhiyun
370*4882a593Smuzhiyun td->has_counter = false;
371*4882a593Smuzhiyun if (get_uint_param(vp->parsed, "counter", &temp_int)) {
372*4882a593Smuzhiyun if (temp_int > 0) {
373*4882a593Smuzhiyun td->has_counter = true;
374*4882a593Smuzhiyun vp->header_size += 4;
375*4882a593Smuzhiyun if (get_uint_param(
376*4882a593Smuzhiyun vp->parsed, "pin_counter", &temp_int)) {
377*4882a593Smuzhiyun if (temp_int > 0)
378*4882a593Smuzhiyun td->pin_counter = true;
379*4882a593Smuzhiyun }
380*4882a593Smuzhiyun }
381*4882a593Smuzhiyun }
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun if (get_uint_param(vp->parsed, "udp", &temp_int)) {
384*4882a593Smuzhiyun if (temp_int > 0) {
385*4882a593Smuzhiyun td->udp = true;
386*4882a593Smuzhiyun vp->header_size += 4;
387*4882a593Smuzhiyun td->counter_offset += 4;
388*4882a593Smuzhiyun td->session_offset += 4;
389*4882a593Smuzhiyun td->cookie_offset += 4;
390*4882a593Smuzhiyun }
391*4882a593Smuzhiyun }
392*4882a593Smuzhiyun
393*4882a593Smuzhiyun vp->rx_header_size = vp->header_size;
394*4882a593Smuzhiyun if ((!td->ipv6) && (!td->udp))
395*4882a593Smuzhiyun vp->rx_header_size += sizeof(struct iphdr);
396*4882a593Smuzhiyun
397*4882a593Smuzhiyun return 0;
398*4882a593Smuzhiyun }
399*4882a593Smuzhiyun
build_raw_transport_data(struct vector_private * vp)400*4882a593Smuzhiyun static int build_raw_transport_data(struct vector_private *vp)
401*4882a593Smuzhiyun {
402*4882a593Smuzhiyun if (uml_raw_enable_vnet_headers(vp->fds->rx_fd)) {
403*4882a593Smuzhiyun if (!uml_raw_enable_vnet_headers(vp->fds->tx_fd))
404*4882a593Smuzhiyun return -1;
405*4882a593Smuzhiyun vp->form_header = &raw_form_header;
406*4882a593Smuzhiyun vp->verify_header = &raw_verify_header;
407*4882a593Smuzhiyun vp->header_size = sizeof(struct virtio_net_hdr);
408*4882a593Smuzhiyun vp->rx_header_size = sizeof(struct virtio_net_hdr);
409*4882a593Smuzhiyun vp->dev->hw_features |= (NETIF_F_TSO | NETIF_F_GRO);
410*4882a593Smuzhiyun vp->dev->features |=
411*4882a593Smuzhiyun (NETIF_F_RXCSUM | NETIF_F_HW_CSUM |
412*4882a593Smuzhiyun NETIF_F_TSO | NETIF_F_GRO);
413*4882a593Smuzhiyun netdev_info(
414*4882a593Smuzhiyun vp->dev,
415*4882a593Smuzhiyun "raw: using vnet headers for tso and tx/rx checksum"
416*4882a593Smuzhiyun );
417*4882a593Smuzhiyun }
418*4882a593Smuzhiyun return 0;
419*4882a593Smuzhiyun }
420*4882a593Smuzhiyun
build_hybrid_transport_data(struct vector_private * vp)421*4882a593Smuzhiyun static int build_hybrid_transport_data(struct vector_private *vp)
422*4882a593Smuzhiyun {
423*4882a593Smuzhiyun if (uml_raw_enable_vnet_headers(vp->fds->rx_fd)) {
424*4882a593Smuzhiyun vp->form_header = &raw_form_header;
425*4882a593Smuzhiyun vp->verify_header = &raw_verify_header;
426*4882a593Smuzhiyun vp->header_size = sizeof(struct virtio_net_hdr);
427*4882a593Smuzhiyun vp->rx_header_size = sizeof(struct virtio_net_hdr);
428*4882a593Smuzhiyun vp->dev->hw_features |=
429*4882a593Smuzhiyun (NETIF_F_TSO | NETIF_F_GSO | NETIF_F_GRO);
430*4882a593Smuzhiyun vp->dev->features |=
431*4882a593Smuzhiyun (NETIF_F_RXCSUM | NETIF_F_HW_CSUM |
432*4882a593Smuzhiyun NETIF_F_TSO | NETIF_F_GSO | NETIF_F_GRO);
433*4882a593Smuzhiyun netdev_info(
434*4882a593Smuzhiyun vp->dev,
435*4882a593Smuzhiyun "tap/raw hybrid: using vnet headers for tso and tx/rx checksum"
436*4882a593Smuzhiyun );
437*4882a593Smuzhiyun } else {
438*4882a593Smuzhiyun return 0; /* do not try to enable tap too if raw failed */
439*4882a593Smuzhiyun }
440*4882a593Smuzhiyun if (uml_tap_enable_vnet_headers(vp->fds->tx_fd))
441*4882a593Smuzhiyun return 0;
442*4882a593Smuzhiyun return -1;
443*4882a593Smuzhiyun }
444*4882a593Smuzhiyun
build_tap_transport_data(struct vector_private * vp)445*4882a593Smuzhiyun static int build_tap_transport_data(struct vector_private *vp)
446*4882a593Smuzhiyun {
447*4882a593Smuzhiyun /* "Pure" tap uses the same fd for rx and tx */
448*4882a593Smuzhiyun if (uml_tap_enable_vnet_headers(vp->fds->tx_fd)) {
449*4882a593Smuzhiyun vp->form_header = &raw_form_header;
450*4882a593Smuzhiyun vp->verify_header = &raw_verify_header;
451*4882a593Smuzhiyun vp->header_size = sizeof(struct virtio_net_hdr);
452*4882a593Smuzhiyun vp->rx_header_size = sizeof(struct virtio_net_hdr);
453*4882a593Smuzhiyun vp->dev->hw_features |=
454*4882a593Smuzhiyun (NETIF_F_TSO | NETIF_F_GSO | NETIF_F_GRO);
455*4882a593Smuzhiyun vp->dev->features |=
456*4882a593Smuzhiyun (NETIF_F_RXCSUM | NETIF_F_HW_CSUM |
457*4882a593Smuzhiyun NETIF_F_TSO | NETIF_F_GSO | NETIF_F_GRO);
458*4882a593Smuzhiyun netdev_info(
459*4882a593Smuzhiyun vp->dev,
460*4882a593Smuzhiyun "tap: using vnet headers for tso and tx/rx checksum"
461*4882a593Smuzhiyun );
462*4882a593Smuzhiyun return 0;
463*4882a593Smuzhiyun }
464*4882a593Smuzhiyun return -1;
465*4882a593Smuzhiyun }
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun
build_bess_transport_data(struct vector_private * vp)468*4882a593Smuzhiyun static int build_bess_transport_data(struct vector_private *vp)
469*4882a593Smuzhiyun {
470*4882a593Smuzhiyun vp->form_header = NULL;
471*4882a593Smuzhiyun vp->verify_header = NULL;
472*4882a593Smuzhiyun vp->header_size = 0;
473*4882a593Smuzhiyun vp->rx_header_size = 0;
474*4882a593Smuzhiyun return 0;
475*4882a593Smuzhiyun }
476*4882a593Smuzhiyun
build_transport_data(struct vector_private * vp)477*4882a593Smuzhiyun int build_transport_data(struct vector_private *vp)
478*4882a593Smuzhiyun {
479*4882a593Smuzhiyun char *transport = uml_vector_fetch_arg(vp->parsed, "transport");
480*4882a593Smuzhiyun
481*4882a593Smuzhiyun if (strncmp(transport, TRANS_GRE, TRANS_GRE_LEN) == 0)
482*4882a593Smuzhiyun return build_gre_transport_data(vp);
483*4882a593Smuzhiyun if (strncmp(transport, TRANS_L2TPV3, TRANS_L2TPV3_LEN) == 0)
484*4882a593Smuzhiyun return build_l2tpv3_transport_data(vp);
485*4882a593Smuzhiyun if (strncmp(transport, TRANS_RAW, TRANS_RAW_LEN) == 0)
486*4882a593Smuzhiyun return build_raw_transport_data(vp);
487*4882a593Smuzhiyun if (strncmp(transport, TRANS_TAP, TRANS_TAP_LEN) == 0)
488*4882a593Smuzhiyun return build_tap_transport_data(vp);
489*4882a593Smuzhiyun if (strncmp(transport, TRANS_HYBRID, TRANS_HYBRID_LEN) == 0)
490*4882a593Smuzhiyun return build_hybrid_transport_data(vp);
491*4882a593Smuzhiyun if (strncmp(transport, TRANS_BESS, TRANS_BESS_LEN) == 0)
492*4882a593Smuzhiyun return build_bess_transport_data(vp);
493*4882a593Smuzhiyun return 0;
494*4882a593Smuzhiyun }
495*4882a593Smuzhiyun
496