]> git.proxmox.com Git - mirror_qemu.git/blob - net/eth.c
Merge tag 'linux-user-for-8.0-pull-request' of https://gitlab.com/laurent_vivier...
[mirror_qemu.git] / net / eth.c
1 /*
2 * QEMU network structures definitions and helper functions
3 *
4 * Copyright (c) 2012 Ravello Systems LTD (http://ravellosystems.com)
5 *
6 * Developed by Daynix Computing LTD (http://www.daynix.com)
7 *
8 * Authors:
9 * Dmitry Fleytman <dmitry@daynix.com>
10 * Tamir Shomer <tamirs@daynix.com>
11 * Yan Vugenfirer <yan@daynix.com>
12 *
13 * This work is licensed under the terms of the GNU GPL, version 2 or later.
14 * See the COPYING file in the top-level directory.
15 *
16 */
17
18 #include "qemu/osdep.h"
19 #include "qemu/log.h"
20 #include "net/eth.h"
21 #include "net/checksum.h"
22 #include "net/tap.h"
23
24 void eth_setup_vlan_headers_ex(struct eth_header *ehdr, uint16_t vlan_tag,
25 uint16_t vlan_ethtype, bool *is_new)
26 {
27 struct vlan_header *vhdr = PKT_GET_VLAN_HDR(ehdr);
28
29 switch (be16_to_cpu(ehdr->h_proto)) {
30 case ETH_P_VLAN:
31 case ETH_P_DVLAN:
32 /* vlan hdr exists */
33 *is_new = false;
34 break;
35
36 default:
37 /* No VLAN header, put a new one */
38 vhdr->h_proto = ehdr->h_proto;
39 ehdr->h_proto = cpu_to_be16(vlan_ethtype);
40 *is_new = true;
41 break;
42 }
43 vhdr->h_tci = cpu_to_be16(vlan_tag);
44 }
45
46 uint8_t
47 eth_get_gso_type(uint16_t l3_proto, uint8_t *l3_hdr, uint8_t l4proto)
48 {
49 uint8_t ecn_state = 0;
50
51 if (l3_proto == ETH_P_IP) {
52 struct ip_header *iphdr = (struct ip_header *) l3_hdr;
53
54 if (IP_HEADER_VERSION(iphdr) == IP_HEADER_VERSION_4) {
55 if (IPTOS_ECN(iphdr->ip_tos) == IPTOS_ECN_CE) {
56 ecn_state = VIRTIO_NET_HDR_GSO_ECN;
57 }
58 if (l4proto == IP_PROTO_TCP) {
59 return VIRTIO_NET_HDR_GSO_TCPV4 | ecn_state;
60 } else if (l4proto == IP_PROTO_UDP) {
61 return VIRTIO_NET_HDR_GSO_UDP | ecn_state;
62 }
63 }
64 } else if (l3_proto == ETH_P_IPV6) {
65 struct ip6_header *ip6hdr = (struct ip6_header *) l3_hdr;
66
67 if (IP6_ECN(ip6hdr->ip6_ecn_acc) == IP6_ECN_CE) {
68 ecn_state = VIRTIO_NET_HDR_GSO_ECN;
69 }
70
71 if (l4proto == IP_PROTO_TCP) {
72 return VIRTIO_NET_HDR_GSO_TCPV6 | ecn_state;
73 }
74 }
75 qemu_log_mask(LOG_UNIMP, "%s: probably not GSO frame, "
76 "unknown L3 protocol: 0x%04"PRIx16"\n", __func__, l3_proto);
77
78 return VIRTIO_NET_HDR_GSO_NONE | ecn_state;
79 }
80
81 uint16_t
82 eth_get_l3_proto(const struct iovec *l2hdr_iov, int iovcnt, size_t l2hdr_len)
83 {
84 uint16_t proto;
85 size_t copied;
86 size_t size = iov_size(l2hdr_iov, iovcnt);
87 size_t proto_offset = l2hdr_len - sizeof(proto);
88
89 if (size < proto_offset) {
90 return ETH_P_UNKNOWN;
91 }
92
93 copied = iov_to_buf(l2hdr_iov, iovcnt, proto_offset,
94 &proto, sizeof(proto));
95
96 return (copied == sizeof(proto)) ? be16_to_cpu(proto) : ETH_P_UNKNOWN;
97 }
98
99 static bool
100 _eth_copy_chunk(size_t input_size,
101 const struct iovec *iov, int iovcnt,
102 size_t offset, size_t length,
103 void *buffer)
104 {
105 size_t copied;
106
107 if (input_size < offset) {
108 return false;
109 }
110
111 copied = iov_to_buf(iov, iovcnt, offset, buffer, length);
112
113 if (copied < length) {
114 return false;
115 }
116
117 return true;
118 }
119
120 static bool
121 _eth_tcp_has_data(bool is_ip4,
122 const struct ip_header *ip4_hdr,
123 const struct ip6_header *ip6_hdr,
124 size_t full_ip6hdr_len,
125 const struct tcp_header *tcp)
126 {
127 uint32_t l4len;
128
129 if (is_ip4) {
130 l4len = be16_to_cpu(ip4_hdr->ip_len) - IP_HDR_GET_LEN(ip4_hdr);
131 } else {
132 size_t opts_len = full_ip6hdr_len - sizeof(struct ip6_header);
133 l4len = be16_to_cpu(ip6_hdr->ip6_ctlun.ip6_un1.ip6_un1_plen) - opts_len;
134 }
135
136 return l4len > TCP_HEADER_DATA_OFFSET(tcp);
137 }
138
139 void eth_get_protocols(const struct iovec *iov, int iovcnt,
140 bool *hasip4, bool *hasip6,
141 size_t *l3hdr_off,
142 size_t *l4hdr_off,
143 size_t *l5hdr_off,
144 eth_ip6_hdr_info *ip6hdr_info,
145 eth_ip4_hdr_info *ip4hdr_info,
146 eth_l4_hdr_info *l4hdr_info)
147 {
148 int proto;
149 bool fragment = false;
150 size_t l2hdr_len = eth_get_l2_hdr_length_iov(iov, iovcnt);
151 size_t input_size = iov_size(iov, iovcnt);
152 size_t copied;
153 uint8_t ip_p;
154
155 *hasip4 = *hasip6 = false;
156 l4hdr_info->proto = ETH_L4_HDR_PROTO_INVALID;
157
158 proto = eth_get_l3_proto(iov, iovcnt, l2hdr_len);
159
160 *l3hdr_off = l2hdr_len;
161
162 if (proto == ETH_P_IP) {
163 struct ip_header *iphdr = &ip4hdr_info->ip4_hdr;
164
165 if (input_size < l2hdr_len) {
166 return;
167 }
168
169 copied = iov_to_buf(iov, iovcnt, l2hdr_len, iphdr, sizeof(*iphdr));
170 if (copied < sizeof(*iphdr) ||
171 IP_HEADER_VERSION(iphdr) != IP_HEADER_VERSION_4) {
172 return;
173 }
174
175 *hasip4 = true;
176 ip_p = iphdr->ip_p;
177 ip4hdr_info->fragment = IP4_IS_FRAGMENT(iphdr);
178 *l4hdr_off = l2hdr_len + IP_HDR_GET_LEN(iphdr);
179
180 fragment = ip4hdr_info->fragment;
181 } else if (proto == ETH_P_IPV6) {
182 if (!eth_parse_ipv6_hdr(iov, iovcnt, l2hdr_len, ip6hdr_info)) {
183 return;
184 }
185
186 *hasip6 = true;
187 ip_p = ip6hdr_info->l4proto;
188 *l4hdr_off = l2hdr_len + ip6hdr_info->full_hdr_len;
189 fragment = ip6hdr_info->fragment;
190 } else {
191 return;
192 }
193
194 if (fragment) {
195 return;
196 }
197
198 switch (ip_p) {
199 case IP_PROTO_TCP:
200 if (_eth_copy_chunk(input_size,
201 iov, iovcnt,
202 *l4hdr_off, sizeof(l4hdr_info->hdr.tcp),
203 &l4hdr_info->hdr.tcp)) {
204 l4hdr_info->proto = ETH_L4_HDR_PROTO_TCP;
205 *l5hdr_off = *l4hdr_off +
206 TCP_HEADER_DATA_OFFSET(&l4hdr_info->hdr.tcp);
207
208 l4hdr_info->has_tcp_data =
209 _eth_tcp_has_data(proto == ETH_P_IP,
210 &ip4hdr_info->ip4_hdr,
211 &ip6hdr_info->ip6_hdr,
212 *l4hdr_off - *l3hdr_off,
213 &l4hdr_info->hdr.tcp);
214 }
215 break;
216
217 case IP_PROTO_UDP:
218 if (_eth_copy_chunk(input_size,
219 iov, iovcnt,
220 *l4hdr_off, sizeof(l4hdr_info->hdr.udp),
221 &l4hdr_info->hdr.udp)) {
222 l4hdr_info->proto = ETH_L4_HDR_PROTO_UDP;
223 *l5hdr_off = *l4hdr_off + sizeof(l4hdr_info->hdr.udp);
224 }
225 break;
226 }
227 }
228
229 size_t
230 eth_strip_vlan(const struct iovec *iov, int iovcnt, size_t iovoff,
231 uint8_t *new_ehdr_buf,
232 uint16_t *payload_offset, uint16_t *tci)
233 {
234 struct vlan_header vlan_hdr;
235 struct eth_header *new_ehdr = (struct eth_header *) new_ehdr_buf;
236
237 size_t copied = iov_to_buf(iov, iovcnt, iovoff,
238 new_ehdr, sizeof(*new_ehdr));
239
240 if (copied < sizeof(*new_ehdr)) {
241 return 0;
242 }
243
244 switch (be16_to_cpu(new_ehdr->h_proto)) {
245 case ETH_P_VLAN:
246 case ETH_P_DVLAN:
247 copied = iov_to_buf(iov, iovcnt, iovoff + sizeof(*new_ehdr),
248 &vlan_hdr, sizeof(vlan_hdr));
249
250 if (copied < sizeof(vlan_hdr)) {
251 return 0;
252 }
253
254 new_ehdr->h_proto = vlan_hdr.h_proto;
255
256 *tci = be16_to_cpu(vlan_hdr.h_tci);
257 *payload_offset = iovoff + sizeof(*new_ehdr) + sizeof(vlan_hdr);
258
259 if (be16_to_cpu(new_ehdr->h_proto) == ETH_P_VLAN) {
260
261 copied = iov_to_buf(iov, iovcnt, *payload_offset,
262 PKT_GET_VLAN_HDR(new_ehdr), sizeof(vlan_hdr));
263
264 if (copied < sizeof(vlan_hdr)) {
265 return 0;
266 }
267
268 *payload_offset += sizeof(vlan_hdr);
269
270 return sizeof(struct eth_header) + sizeof(struct vlan_header);
271 } else {
272 return sizeof(struct eth_header);
273 }
274 default:
275 return 0;
276 }
277 }
278
279 size_t
280 eth_strip_vlan_ex(const struct iovec *iov, int iovcnt, size_t iovoff,
281 uint16_t vet, uint8_t *new_ehdr_buf,
282 uint16_t *payload_offset, uint16_t *tci)
283 {
284 struct vlan_header vlan_hdr;
285 struct eth_header *new_ehdr = (struct eth_header *) new_ehdr_buf;
286
287 size_t copied = iov_to_buf(iov, iovcnt, iovoff,
288 new_ehdr, sizeof(*new_ehdr));
289
290 if (copied < sizeof(*new_ehdr)) {
291 return 0;
292 }
293
294 if (be16_to_cpu(new_ehdr->h_proto) == vet) {
295 copied = iov_to_buf(iov, iovcnt, iovoff + sizeof(*new_ehdr),
296 &vlan_hdr, sizeof(vlan_hdr));
297
298 if (copied < sizeof(vlan_hdr)) {
299 return 0;
300 }
301
302 new_ehdr->h_proto = vlan_hdr.h_proto;
303
304 *tci = be16_to_cpu(vlan_hdr.h_tci);
305 *payload_offset = iovoff + sizeof(*new_ehdr) + sizeof(vlan_hdr);
306 return sizeof(struct eth_header);
307 }
308
309 return 0;
310 }
311
312 void
313 eth_fix_ip4_checksum(void *l3hdr, size_t l3hdr_len)
314 {
315 struct ip_header *iphdr = (struct ip_header *) l3hdr;
316 iphdr->ip_sum = 0;
317 iphdr->ip_sum = cpu_to_be16(net_raw_checksum(l3hdr, l3hdr_len));
318 }
319
320 uint32_t
321 eth_calc_ip4_pseudo_hdr_csum(struct ip_header *iphdr,
322 uint16_t csl,
323 uint32_t *cso)
324 {
325 struct ip_pseudo_header ipph;
326 ipph.ip_src = iphdr->ip_src;
327 ipph.ip_dst = iphdr->ip_dst;
328 ipph.ip_payload = cpu_to_be16(csl);
329 ipph.ip_proto = iphdr->ip_p;
330 ipph.zeros = 0;
331 *cso = sizeof(ipph);
332 return net_checksum_add(*cso, (uint8_t *) &ipph);
333 }
334
335 uint32_t
336 eth_calc_ip6_pseudo_hdr_csum(struct ip6_header *iphdr,
337 uint16_t csl,
338 uint8_t l4_proto,
339 uint32_t *cso)
340 {
341 struct ip6_pseudo_header ipph;
342 ipph.ip6_src = iphdr->ip6_src;
343 ipph.ip6_dst = iphdr->ip6_dst;
344 ipph.len = cpu_to_be16(csl);
345 ipph.zero[0] = 0;
346 ipph.zero[1] = 0;
347 ipph.zero[2] = 0;
348 ipph.next_hdr = l4_proto;
349 *cso = sizeof(ipph);
350 return net_checksum_add(*cso, (uint8_t *)&ipph);
351 }
352
353 static bool
354 eth_is_ip6_extension_header_type(uint8_t hdr_type)
355 {
356 switch (hdr_type) {
357 case IP6_HOP_BY_HOP:
358 case IP6_ROUTING:
359 case IP6_FRAGMENT:
360 case IP6_AUTHENTICATION:
361 case IP6_DESTINATON:
362 case IP6_MOBILITY:
363 return true;
364 default:
365 return false;
366 }
367 }
368
369 static bool
370 _eth_get_rss_ex_dst_addr(const struct iovec *pkt, int pkt_frags,
371 size_t ext_hdr_offset,
372 struct ip6_ext_hdr *ext_hdr,
373 struct in6_address *dst_addr)
374 {
375 struct ip6_ext_hdr_routing rt_hdr;
376 size_t input_size = iov_size(pkt, pkt_frags);
377 size_t bytes_read;
378
379 if (input_size < ext_hdr_offset + sizeof(rt_hdr) + sizeof(*dst_addr)) {
380 return false;
381 }
382
383 bytes_read = iov_to_buf(pkt, pkt_frags, ext_hdr_offset,
384 &rt_hdr, sizeof(rt_hdr));
385 assert(bytes_read == sizeof(rt_hdr));
386 if ((rt_hdr.rtype != 2) || (rt_hdr.segleft != 1)) {
387 return false;
388 }
389 bytes_read = iov_to_buf(pkt, pkt_frags, ext_hdr_offset + sizeof(rt_hdr),
390 dst_addr, sizeof(*dst_addr));
391 assert(bytes_read == sizeof(*dst_addr));
392
393 return true;
394 }
395
396 static bool
397 _eth_get_rss_ex_src_addr(const struct iovec *pkt, int pkt_frags,
398 size_t dsthdr_offset,
399 struct ip6_ext_hdr *ext_hdr,
400 struct in6_address *src_addr)
401 {
402 size_t bytes_left = (ext_hdr->ip6r_len + 1) * 8 - sizeof(*ext_hdr);
403 struct ip6_option_hdr opthdr;
404 size_t opt_offset = dsthdr_offset + sizeof(*ext_hdr);
405
406 while (bytes_left > sizeof(opthdr)) {
407 size_t input_size = iov_size(pkt, pkt_frags);
408 size_t bytes_read, optlen;
409
410 if (input_size < opt_offset) {
411 return false;
412 }
413
414 bytes_read = iov_to_buf(pkt, pkt_frags, opt_offset,
415 &opthdr, sizeof(opthdr));
416
417 if (bytes_read != sizeof(opthdr)) {
418 return false;
419 }
420
421 optlen = (opthdr.type == IP6_OPT_PAD1) ? 1
422 : (opthdr.len + sizeof(opthdr));
423
424 if (optlen > bytes_left) {
425 return false;
426 }
427
428 if (opthdr.type == IP6_OPT_HOME) {
429 size_t input_size = iov_size(pkt, pkt_frags);
430
431 if (input_size < opt_offset + sizeof(opthdr)) {
432 return false;
433 }
434
435 bytes_read = iov_to_buf(pkt, pkt_frags,
436 opt_offset + sizeof(opthdr),
437 src_addr, sizeof(*src_addr));
438
439 return bytes_read == sizeof(*src_addr);
440 }
441
442 opt_offset += optlen;
443 bytes_left -= optlen;
444 }
445
446 return false;
447 }
448
449 bool eth_parse_ipv6_hdr(const struct iovec *pkt, int pkt_frags,
450 size_t ip6hdr_off, eth_ip6_hdr_info *info)
451 {
452 struct ip6_ext_hdr ext_hdr;
453 size_t bytes_read;
454 uint8_t curr_ext_hdr_type;
455 size_t input_size = iov_size(pkt, pkt_frags);
456
457 info->rss_ex_dst_valid = false;
458 info->rss_ex_src_valid = false;
459 info->fragment = false;
460
461 if (input_size < ip6hdr_off) {
462 return false;
463 }
464
465 bytes_read = iov_to_buf(pkt, pkt_frags, ip6hdr_off,
466 &info->ip6_hdr, sizeof(info->ip6_hdr));
467 if (bytes_read < sizeof(info->ip6_hdr)) {
468 return false;
469 }
470
471 info->full_hdr_len = sizeof(struct ip6_header);
472
473 curr_ext_hdr_type = info->ip6_hdr.ip6_nxt;
474
475 if (!eth_is_ip6_extension_header_type(curr_ext_hdr_type)) {
476 info->l4proto = info->ip6_hdr.ip6_nxt;
477 info->has_ext_hdrs = false;
478 return true;
479 }
480
481 info->has_ext_hdrs = true;
482
483 do {
484 if (input_size < ip6hdr_off + info->full_hdr_len) {
485 return false;
486 }
487
488 bytes_read = iov_to_buf(pkt, pkt_frags, ip6hdr_off + info->full_hdr_len,
489 &ext_hdr, sizeof(ext_hdr));
490
491 if (bytes_read < sizeof(ext_hdr)) {
492 return false;
493 }
494
495 if (curr_ext_hdr_type == IP6_ROUTING) {
496 if (ext_hdr.ip6r_len == sizeof(struct in6_address) / 8) {
497 info->rss_ex_dst_valid =
498 _eth_get_rss_ex_dst_addr(pkt, pkt_frags,
499 ip6hdr_off + info->full_hdr_len,
500 &ext_hdr, &info->rss_ex_dst);
501 }
502 } else if (curr_ext_hdr_type == IP6_DESTINATON) {
503 info->rss_ex_src_valid =
504 _eth_get_rss_ex_src_addr(pkt, pkt_frags,
505 ip6hdr_off + info->full_hdr_len,
506 &ext_hdr, &info->rss_ex_src);
507 } else if (curr_ext_hdr_type == IP6_FRAGMENT) {
508 info->fragment = true;
509 }
510
511 info->full_hdr_len += (ext_hdr.ip6r_len + 1) * IP6_EXT_GRANULARITY;
512 curr_ext_hdr_type = ext_hdr.ip6r_nxt;
513 } while (eth_is_ip6_extension_header_type(curr_ext_hdr_type));
514
515 info->l4proto = ext_hdr.ip6r_nxt;
516 return true;
517 }
518
519 bool eth_pad_short_frame(uint8_t *padded_pkt, size_t *padded_buflen,
520 const void *pkt, size_t pkt_size)
521 {
522 assert(padded_buflen && *padded_buflen >= ETH_ZLEN);
523
524 if (pkt_size >= ETH_ZLEN) {
525 return false;
526 }
527
528 /* pad to minimum Ethernet frame length */
529 memcpy(padded_pkt, pkt, pkt_size);
530 memset(&padded_pkt[pkt_size], 0, ETH_ZLEN - pkt_size);
531 *padded_buflen = ETH_ZLEN;
532
533 return true;
534 }