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

source code of linux/arch/um/drivers/vector_transports.c