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 | * Portions developed by Free Software Foundation, Inc |
9 | * Copyright (C) 1991-1997, 2001, 2003, 2006 Free Software Foundation, Inc. |
10 | * See netinet/ip6.h and netinet/in.h (GNU C Library) |
11 | * |
12 | * Portions developed by Igor Kovalenko |
13 | * Copyright (c) 2006 Igor Kovalenko |
14 | * See hw/rtl8139.c (QEMU) |
15 | * |
16 | * Authors: |
17 | * Dmitry Fleytman <dmitry@daynix.com> |
18 | * Tamir Shomer <tamirs@daynix.com> |
19 | * Yan Vugenfirer <yan@daynix.com> |
20 | * |
21 | * This work is licensed under the terms of the GNU GPL, version 2 or later. |
22 | * See the COPYING file in the top-level directory. |
23 | * |
24 | */ |
25 | |
26 | #ifndef QEMU_ETH_H |
27 | #define QEMU_ETH_H |
28 | |
29 | #include "qemu/bswap.h" |
30 | #include "qemu/iov.h" |
31 | |
32 | #define ETH_ALEN 6 |
33 | #define ETH_HLEN 14 |
34 | |
35 | struct { |
36 | uint8_t [ETH_ALEN]; /* destination eth addr */ |
37 | uint8_t [ETH_ALEN]; /* source ether addr */ |
38 | uint16_t ; /* packet type ID field */ |
39 | }; |
40 | |
41 | struct { |
42 | uint16_t ; /* priority and VLAN ID */ |
43 | uint16_t ; /* encapsulated protocol */ |
44 | }; |
45 | |
46 | struct { |
47 | uint8_t ; /* version and header length */ |
48 | uint8_t ; /* type of service */ |
49 | uint16_t ; /* total length */ |
50 | uint16_t ; /* identification */ |
51 | uint16_t ; /* fragment offset field */ |
52 | uint8_t ; /* time to live */ |
53 | uint8_t ; /* protocol */ |
54 | uint16_t ; /* checksum */ |
55 | uint32_t , ; /* source and destination address */ |
56 | }; |
57 | |
58 | typedef struct { |
59 | uint16_t ; /* source port */ |
60 | uint16_t ; /* destination port */ |
61 | uint32_t ; /* sequence number */ |
62 | uint32_t ; /* acknowledgment number */ |
63 | uint16_t ; /* data offset, reserved 6 bits, */ |
64 | /* TCP protocol flags */ |
65 | uint16_t ; /* window */ |
66 | uint16_t ; /* checksum */ |
67 | uint16_t ; /* urgent pointer */ |
68 | } ; |
69 | |
70 | #define TCP_FLAGS_ONLY(flags) ((flags) & 0x3f) |
71 | |
72 | #define (tcp) \ |
73 | TCP_FLAGS_ONLY(be16_to_cpu((tcp)->th_offset_flags)) |
74 | |
75 | #define TCP_FLAG_ACK 0x10 |
76 | |
77 | #define (tcp) \ |
78 | (((be16_to_cpu((tcp)->th_offset_flags) >> 12) & 0xf) << 2) |
79 | |
80 | typedef struct { |
81 | uint16_t ; /* source port */ |
82 | uint16_t ; /* destination port */ |
83 | uint16_t ; /* udp length */ |
84 | uint16_t ; /* udp checksum */ |
85 | } ; |
86 | |
87 | typedef struct { |
88 | uint32_t ; |
89 | uint32_t ; |
90 | uint8_t ; |
91 | uint8_t ; |
92 | uint16_t ; |
93 | } ; |
94 | |
95 | /* IPv6 address */ |
96 | struct in6_address { |
97 | union { |
98 | uint8_t __u6_addr8[16]; |
99 | } __in6_u; |
100 | }; |
101 | |
102 | struct { |
103 | union { |
104 | struct ip6_hdrctl { |
105 | uint32_t ip6_un1_flow; /* 4 bits version, 8 bits TC, |
106 | 20 bits flow-ID */ |
107 | uint16_t ip6_un1_plen; /* payload length */ |
108 | uint8_t ip6_un1_nxt; /* next header */ |
109 | uint8_t ip6_un1_hlim; /* hop limit */ |
110 | } ; |
111 | uint8_t ; /* 4 bits version, top 4 bits tclass */ |
112 | struct ip6_ecn_access { |
113 | uint8_t ip6_un3_vfc; /* 4 bits version, top 4 bits tclass */ |
114 | uint8_t ip6_un3_ecn; /* 2 bits ECN, top 6 bits payload length */ |
115 | } ; |
116 | } ; |
117 | struct in6_address ; /* source address */ |
118 | struct in6_address ; /* destination address */ |
119 | }; |
120 | |
121 | typedef struct { |
122 | struct in6_address ; |
123 | struct in6_address ; |
124 | uint32_t ; |
125 | uint8_t [3]; |
126 | uint8_t ; |
127 | } ; |
128 | |
129 | struct ip6_ext_hdr { |
130 | uint8_t ip6r_nxt; /* next header */ |
131 | uint8_t ip6r_len; /* length in units of 8 octets */ |
132 | }; |
133 | |
134 | struct ip6_ext_hdr_routing { |
135 | uint8_t nxt; |
136 | uint8_t len; |
137 | uint8_t rtype; |
138 | uint8_t segleft; |
139 | uint8_t rsvd[4]; |
140 | }; |
141 | |
142 | struct ip6_option_hdr { |
143 | #define IP6_OPT_PAD1 (0x00) |
144 | #define IP6_OPT_HOME (0xC9) |
145 | uint8_t type; |
146 | uint8_t len; |
147 | }; |
148 | |
149 | struct udp_hdr { |
150 | uint16_t uh_sport; /* source port */ |
151 | uint16_t uh_dport; /* destination port */ |
152 | uint16_t uh_ulen; /* udp length */ |
153 | uint16_t uh_sum; /* udp checksum */ |
154 | }; |
155 | |
156 | struct tcp_hdr { |
157 | u_short th_sport; /* source port */ |
158 | u_short th_dport; /* destination port */ |
159 | uint32_t th_seq; /* sequence number */ |
160 | uint32_t th_ack; /* acknowledgment number */ |
161 | #ifdef HOST_WORDS_BIGENDIAN |
162 | u_char th_off : 4, /* data offset */ |
163 | th_x2:4; /* (unused) */ |
164 | #else |
165 | u_char th_x2 : 4, /* (unused) */ |
166 | th_off:4; /* data offset */ |
167 | #endif |
168 | |
169 | #define TH_ELN 0x1 /* explicit loss notification */ |
170 | #define TH_ECN 0x2 /* explicit congestion notification */ |
171 | #define TH_FS 0x4 /* fast start */ |
172 | |
173 | u_char th_flags; |
174 | #define TH_FIN 0x01 |
175 | #define TH_SYN 0x02 |
176 | #define TH_RST 0x04 |
177 | #define TH_PUSH 0x08 |
178 | #define TH_ACK 0x10 |
179 | #define TH_URG 0x20 |
180 | #define TH_ECE 0x40 |
181 | #define TH_CWR 0x80 |
182 | u_short th_win; /* window */ |
183 | u_short th_sum; /* checksum */ |
184 | u_short th_urp; /* urgent pointer */ |
185 | }; |
186 | |
187 | #define ip6_nxt ip6_ctlun.ip6_un1.ip6_un1_nxt |
188 | #define ip6_ecn_acc ip6_ctlun.ip6_un3.ip6_un3_ecn |
189 | |
190 | #define PKT_GET_ETH_HDR(p) \ |
191 | ((struct eth_header *)(p)) |
192 | #define PKT_GET_VLAN_HDR(p) \ |
193 | ((struct vlan_header *) (((uint8_t *)(p)) + sizeof(struct eth_header))) |
194 | #define PKT_GET_DVLAN_HDR(p) \ |
195 | (PKT_GET_VLAN_HDR(p) + 1) |
196 | #define PKT_GET_IP_HDR(p) \ |
197 | ((struct ip_header *)(((uint8_t *)(p)) + eth_get_l2_hdr_length(p))) |
198 | #define IP_HDR_GET_LEN(p) \ |
199 | ((ldub_p(p + offsetof(struct ip_header, ip_ver_len)) & 0x0F) << 2) |
200 | #define IP_HDR_GET_P(p) \ |
201 | (ldub_p(p + offsetof(struct ip_header, ip_p))) |
202 | #define PKT_GET_IP_HDR_LEN(p) \ |
203 | (IP_HDR_GET_LEN(PKT_GET_IP_HDR(p))) |
204 | #define PKT_GET_IP6_HDR(p) \ |
205 | ((struct ip6_header *) (((uint8_t *)(p)) + eth_get_l2_hdr_length(p))) |
206 | #define (ip) \ |
207 | (((ip)->ip_ver_len >> 4) & 0xf) |
208 | #define IP4_IS_FRAGMENT(ip) \ |
209 | ((be16_to_cpu((ip)->ip_off) & (IP_OFFMASK | IP_MF)) != 0) |
210 | |
211 | #define ETH_P_IP (0x0800) /* Internet Protocol packet */ |
212 | #define ETH_P_ARP (0x0806) /* Address Resolution packet */ |
213 | #define ETH_P_IPV6 (0x86dd) |
214 | #define ETH_P_VLAN (0x8100) |
215 | #define ETH_P_DVLAN (0x88a8) |
216 | #define ETH_P_NCSI (0x88f8) |
217 | #define ETH_P_UNKNOWN (0xffff) |
218 | #define VLAN_VID_MASK 0x0fff |
219 | #define (4) |
220 | #define (6) |
221 | #define IP_PROTO_TCP (6) |
222 | #define IP_PROTO_UDP (17) |
223 | #define IPTOS_ECN_MASK 0x03 |
224 | #define IPTOS_ECN(x) ((x) & IPTOS_ECN_MASK) |
225 | #define IPTOS_ECN_CE 0x03 |
226 | #define IP6_ECN_MASK 0xC0 |
227 | #define IP6_ECN(x) ((x) & IP6_ECN_MASK) |
228 | #define IP6_ECN_CE 0xC0 |
229 | #define IP4_DONT_FRAGMENT_FLAG (1 << 14) |
230 | |
231 | #define IS_SPECIAL_VLAN_ID(x) \ |
232 | (((x) == 0) || ((x) == 0xFFF)) |
233 | |
234 | #define ETH_MAX_L2_HDR_LEN \ |
235 | (sizeof(struct eth_header) + 2 * sizeof(struct vlan_header)) |
236 | |
237 | #define ETH_MAX_IP4_HDR_LEN (60) |
238 | #define ETH_MAX_IP_DGRAM_LEN (0xFFFF) |
239 | |
240 | #define IP_FRAG_UNIT_SIZE (8) |
241 | #define IP_FRAG_ALIGN_SIZE(x) ((x) & ~0x7) |
242 | #define IP_RF 0x8000 /* reserved fragment flag */ |
243 | #define IP_DF 0x4000 /* don't fragment flag */ |
244 | #define IP_MF 0x2000 /* more fragments flag */ |
245 | #define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ |
246 | |
247 | #define IP6_EXT_GRANULARITY (8) /* Size granularity for |
248 | IPv6 extension headers */ |
249 | |
250 | /* IP6 extension header types */ |
251 | #define IP6_HOP_BY_HOP (0) |
252 | #define IP6_ROUTING (43) |
253 | #define IP6_FRAGMENT (44) |
254 | #define IP6_ESP (50) |
255 | #define IP6_AUTHENTICATION (51) |
256 | #define IP6_NONE (59) |
257 | #define IP6_DESTINATON (60) |
258 | #define IP6_MOBILITY (135) |
259 | |
260 | static inline int is_multicast_ether_addr(const uint8_t *addr) |
261 | { |
262 | return 0x01 & addr[0]; |
263 | } |
264 | |
265 | static inline int is_broadcast_ether_addr(const uint8_t *addr) |
266 | { |
267 | return (addr[0] & addr[1] & addr[2] & addr[3] & addr[4] & addr[5]) == 0xff; |
268 | } |
269 | |
270 | static inline int is_unicast_ether_addr(const uint8_t *addr) |
271 | { |
272 | return !is_multicast_ether_addr(addr); |
273 | } |
274 | |
275 | typedef enum { |
276 | ETH_PKT_UCAST = 0xAABBCC00, |
277 | ETH_PKT_BCAST, |
278 | ETH_PKT_MCAST |
279 | } eth_pkt_types_e; |
280 | |
281 | static inline eth_pkt_types_e |
282 | get_eth_packet_type(const struct eth_header *ehdr) |
283 | { |
284 | if (is_broadcast_ether_addr(ehdr->h_dest)) { |
285 | return ETH_PKT_BCAST; |
286 | } else if (is_multicast_ether_addr(ehdr->h_dest)) { |
287 | return ETH_PKT_MCAST; |
288 | } else { /* unicast */ |
289 | return ETH_PKT_UCAST; |
290 | } |
291 | } |
292 | |
293 | static inline uint32_t |
294 | eth_get_l2_hdr_length(const void *p) |
295 | { |
296 | uint16_t proto = be16_to_cpu(PKT_GET_ETH_HDR(p)->h_proto); |
297 | struct vlan_header *hvlan = PKT_GET_VLAN_HDR(p); |
298 | switch (proto) { |
299 | case ETH_P_VLAN: |
300 | return sizeof(struct eth_header) + sizeof(struct vlan_header); |
301 | case ETH_P_DVLAN: |
302 | if (be16_to_cpu(hvlan->h_proto) == ETH_P_VLAN) { |
303 | return sizeof(struct eth_header) + 2 * sizeof(struct vlan_header); |
304 | } else { |
305 | return sizeof(struct eth_header) + sizeof(struct vlan_header); |
306 | } |
307 | default: |
308 | return sizeof(struct eth_header); |
309 | } |
310 | } |
311 | |
312 | static inline uint32_t |
313 | eth_get_l2_hdr_length_iov(const struct iovec *iov, int iovcnt) |
314 | { |
315 | uint8_t p[sizeof(struct eth_header) + sizeof(struct vlan_header)]; |
316 | size_t copied = iov_to_buf(iov, iovcnt, 0, p, ARRAY_SIZE(p)); |
317 | |
318 | if (copied < ARRAY_SIZE(p)) { |
319 | return copied; |
320 | } |
321 | |
322 | return eth_get_l2_hdr_length(p); |
323 | } |
324 | |
325 | static inline uint16_t |
326 | eth_get_pkt_tci(const void *p) |
327 | { |
328 | uint16_t proto = be16_to_cpu(PKT_GET_ETH_HDR(p)->h_proto); |
329 | struct vlan_header *hvlan = PKT_GET_VLAN_HDR(p); |
330 | switch (proto) { |
331 | case ETH_P_VLAN: |
332 | case ETH_P_DVLAN: |
333 | return be16_to_cpu(hvlan->h_tci); |
334 | default: |
335 | return 0; |
336 | } |
337 | } |
338 | |
339 | size_t |
340 | eth_strip_vlan(const struct iovec *iov, int iovcnt, size_t iovoff, |
341 | uint8_t *new_ehdr_buf, |
342 | uint16_t *payload_offset, uint16_t *tci); |
343 | |
344 | size_t |
345 | eth_strip_vlan_ex(const struct iovec *iov, int iovcnt, size_t iovoff, |
346 | uint16_t vet, uint8_t *new_ehdr_buf, |
347 | uint16_t *payload_offset, uint16_t *tci); |
348 | |
349 | uint16_t |
350 | eth_get_l3_proto(const struct iovec *l2hdr_iov, int iovcnt, size_t l2hdr_len); |
351 | |
352 | void (struct eth_header *ehdr, uint16_t vlan_tag, |
353 | uint16_t vlan_ethtype, bool *is_new); |
354 | |
355 | static inline void |
356 | (struct eth_header *ehdr, uint16_t vlan_tag, |
357 | bool *is_new) |
358 | { |
359 | eth_setup_vlan_headers_ex(ehdr, vlan_tag, ETH_P_VLAN, is_new); |
360 | } |
361 | |
362 | |
363 | uint8_t eth_get_gso_type(uint16_t l3_proto, uint8_t *l3_hdr, uint8_t l4proto); |
364 | |
365 | typedef struct eth_ip6_hdr_info_st { |
366 | uint8_t l4proto; |
367 | size_t full_hdr_len; |
368 | struct ip6_header ip6_hdr; |
369 | bool has_ext_hdrs; |
370 | bool ; |
371 | struct in6_address ; |
372 | bool ; |
373 | struct in6_address ; |
374 | bool fragment; |
375 | } eth_ip6_hdr_info; |
376 | |
377 | typedef struct eth_ip4_hdr_info_st { |
378 | struct ip_header ip4_hdr; |
379 | bool fragment; |
380 | } eth_ip4_hdr_info; |
381 | |
382 | typedef struct eth_l4_hdr_info_st { |
383 | union { |
384 | struct tcp_header tcp; |
385 | struct udp_header udp; |
386 | } hdr; |
387 | |
388 | bool has_tcp_data; |
389 | } eth_l4_hdr_info; |
390 | |
391 | void eth_get_protocols(const struct iovec *iov, int iovcnt, |
392 | bool *isip4, bool *isip6, |
393 | bool *isudp, bool *istcp, |
394 | size_t *l3hdr_off, |
395 | size_t *l4hdr_off, |
396 | size_t *l5hdr_off, |
397 | eth_ip6_hdr_info *ip6hdr_info, |
398 | eth_ip4_hdr_info *ip4hdr_info, |
399 | eth_l4_hdr_info *l4hdr_info); |
400 | |
401 | void eth_setup_ip4_fragmentation(const void *l2hdr, size_t l2hdr_len, |
402 | void *l3hdr, size_t l3hdr_len, |
403 | size_t l3payload_len, |
404 | size_t frag_offset, bool more_frags); |
405 | |
406 | void |
407 | eth_fix_ip4_checksum(void *l3hdr, size_t l3hdr_len); |
408 | |
409 | uint32_t |
410 | eth_calc_ip4_pseudo_hdr_csum(struct ip_header *iphdr, |
411 | uint16_t csl, |
412 | uint32_t *cso); |
413 | |
414 | uint32_t |
415 | eth_calc_ip6_pseudo_hdr_csum(struct ip6_header *iphdr, |
416 | uint16_t csl, |
417 | uint8_t l4_proto, |
418 | uint32_t *cso); |
419 | |
420 | bool |
421 | eth_parse_ipv6_hdr(const struct iovec *pkt, int pkt_frags, |
422 | size_t ip6hdr_off, eth_ip6_hdr_info *info); |
423 | |
424 | #endif |
425 | |