]>
Commit | Line | Data |
---|---|---|
75020a70 DF |
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 <[email protected]> | |
18 | * Tamir Shomer <[email protected]> | |
19 | * Yan Vugenfirer <[email protected]> | |
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 | ||
75020a70 DF |
29 | #include "qemu/bswap.h" |
30 | #include "qemu/iov.h" | |
31 | ||
32 | #define ETH_ALEN 6 | |
9c7ffe26 | 33 | #define ETH_HLEN 14 |
75020a70 DF |
34 | |
35 | struct eth_header { | |
36 | uint8_t h_dest[ETH_ALEN]; /* destination eth addr */ | |
37 | uint8_t h_source[ETH_ALEN]; /* source ether addr */ | |
38 | uint16_t h_proto; /* packet type ID field */ | |
39 | }; | |
40 | ||
41 | struct vlan_header { | |
42 | uint16_t h_tci; /* priority and VLAN ID */ | |
43 | uint16_t h_proto; /* encapsulated protocol */ | |
44 | }; | |
45 | ||
46 | struct ip_header { | |
47 | uint8_t ip_ver_len; /* version and header length */ | |
48 | uint8_t ip_tos; /* type of service */ | |
49 | uint16_t ip_len; /* total length */ | |
50 | uint16_t ip_id; /* identification */ | |
51 | uint16_t ip_off; /* fragment offset field */ | |
52 | uint8_t ip_ttl; /* time to live */ | |
53 | uint8_t ip_p; /* protocol */ | |
54 | uint16_t ip_sum; /* checksum */ | |
55 | uint32_t ip_src, ip_dst; /* source and destination address */ | |
56 | }; | |
57 | ||
58 | typedef struct tcp_header { | |
59 | uint16_t th_sport; /* source port */ | |
60 | uint16_t th_dport; /* destination port */ | |
61 | uint32_t th_seq; /* sequence number */ | |
62 | uint32_t th_ack; /* acknowledgment number */ | |
63 | uint16_t th_offset_flags; /* data offset, reserved 6 bits, */ | |
64 | /* TCP protocol flags */ | |
65 | uint16_t th_win; /* window */ | |
66 | uint16_t th_sum; /* checksum */ | |
67 | uint16_t th_urp; /* urgent pointer */ | |
68 | } tcp_header; | |
69 | ||
70 | typedef struct udp_header { | |
71 | uint16_t uh_sport; /* source port */ | |
72 | uint16_t uh_dport; /* destination port */ | |
73 | uint16_t uh_ulen; /* udp length */ | |
74 | uint16_t uh_sum; /* udp checksum */ | |
75 | } udp_header; | |
76 | ||
77 | typedef struct ip_pseudo_header { | |
78 | uint32_t ip_src; | |
79 | uint32_t ip_dst; | |
80 | uint8_t zeros; | |
81 | uint8_t ip_proto; | |
82 | uint16_t ip_payload; | |
83 | } ip_pseudo_header; | |
84 | ||
85 | /* IPv6 address */ | |
d60b20cf | 86 | struct in6_address { |
75020a70 DF |
87 | union { |
88 | uint8_t __u6_addr8[16]; | |
89 | } __in6_u; | |
90 | }; | |
91 | ||
92 | struct ip6_header { | |
93 | union { | |
94 | struct ip6_hdrctl { | |
95 | uint32_t ip6_un1_flow; /* 4 bits version, 8 bits TC, | |
96 | 20 bits flow-ID */ | |
97 | uint16_t ip6_un1_plen; /* payload length */ | |
98 | uint8_t ip6_un1_nxt; /* next header */ | |
99 | uint8_t ip6_un1_hlim; /* hop limit */ | |
100 | } ip6_un1; | |
101 | uint8_t ip6_un2_vfc; /* 4 bits version, top 4 bits tclass */ | |
102 | struct ip6_ecn_access { | |
103 | uint8_t ip6_un3_vfc; /* 4 bits version, top 4 bits tclass */ | |
104 | uint8_t ip6_un3_ecn; /* 2 bits ECN, top 6 bits payload length */ | |
105 | } ip6_un3; | |
106 | } ip6_ctlun; | |
d60b20cf DK |
107 | struct in6_address ip6_src; /* source address */ |
108 | struct in6_address ip6_dst; /* destination address */ | |
75020a70 DF |
109 | }; |
110 | ||
111 | struct ip6_ext_hdr { | |
112 | uint8_t ip6r_nxt; /* next header */ | |
113 | uint8_t ip6r_len; /* length in units of 8 octets */ | |
114 | }; | |
115 | ||
116 | struct udp_hdr { | |
117 | uint16_t uh_sport; /* source port */ | |
118 | uint16_t uh_dport; /* destination port */ | |
119 | uint16_t uh_ulen; /* udp length */ | |
120 | uint16_t uh_sum; /* udp checksum */ | |
121 | }; | |
122 | ||
123 | struct tcp_hdr { | |
124 | u_short th_sport; /* source port */ | |
125 | u_short th_dport; /* destination port */ | |
126 | uint32_t th_seq; /* sequence number */ | |
127 | uint32_t th_ack; /* acknowledgment number */ | |
128 | #ifdef HOST_WORDS_BIGENDIAN | |
129 | u_char th_off : 4, /* data offset */ | |
130 | th_x2:4; /* (unused) */ | |
131 | #else | |
132 | u_char th_x2 : 4, /* (unused) */ | |
133 | th_off:4; /* data offset */ | |
134 | #endif | |
135 | ||
136 | #define TH_ELN 0x1 /* explicit loss notification */ | |
137 | #define TH_ECN 0x2 /* explicit congestion notification */ | |
138 | #define TH_FS 0x4 /* fast start */ | |
139 | ||
140 | u_char th_flags; | |
141 | #define TH_FIN 0x01 | |
142 | #define TH_SYN 0x02 | |
143 | #define TH_RST 0x04 | |
144 | #define TH_PUSH 0x08 | |
145 | #define TH_ACK 0x10 | |
146 | #define TH_URG 0x20 | |
147 | u_short th_win; /* window */ | |
148 | u_short th_sum; /* checksum */ | |
149 | u_short th_urp; /* urgent pointer */ | |
150 | }; | |
151 | ||
152 | #define ip6_nxt ip6_ctlun.ip6_un1.ip6_un1_nxt | |
153 | #define ip6_ecn_acc ip6_ctlun.ip6_un3.ip6_un3_ecn | |
154 | ||
155 | #define PKT_GET_ETH_HDR(p) \ | |
156 | ((struct eth_header *)(p)) | |
157 | #define PKT_GET_VLAN_HDR(p) \ | |
158 | ((struct vlan_header *) (((uint8_t *)(p)) + sizeof(struct eth_header))) | |
159 | #define PKT_GET_DVLAN_HDR(p) \ | |
160 | (PKT_GET_VLAN_HDR(p) + 1) | |
161 | #define PKT_GET_IP_HDR(p) \ | |
162 | ((struct ip_header *)(((uint8_t *)(p)) + eth_get_l2_hdr_length(p))) | |
163 | #define IP_HDR_GET_LEN(p) \ | |
164 | ((((struct ip_header *)p)->ip_ver_len & 0x0F) << 2) | |
165 | #define PKT_GET_IP_HDR_LEN(p) \ | |
166 | (IP_HDR_GET_LEN(PKT_GET_IP_HDR(p))) | |
167 | #define PKT_GET_IP6_HDR(p) \ | |
168 | ((struct ip6_header *) (((uint8_t *)(p)) + eth_get_l2_hdr_length(p))) | |
169 | #define IP_HEADER_VERSION(ip) \ | |
170 | ((ip->ip_ver_len >> 4)&0xf) | |
171 | ||
9c7ffe26 DDAG |
172 | #define ETH_P_IP (0x0800) /* Internet Protocol packet */ |
173 | #define ETH_P_ARP (0x0806) /* Address Resolution packet */ | |
75020a70 DF |
174 | #define ETH_P_IPV6 (0x86dd) |
175 | #define ETH_P_VLAN (0x8100) | |
176 | #define ETH_P_DVLAN (0x88a8) | |
177 | #define VLAN_VID_MASK 0x0fff | |
178 | #define IP_HEADER_VERSION_4 (4) | |
179 | #define IP_HEADER_VERSION_6 (6) | |
180 | #define IP_PROTO_TCP (6) | |
181 | #define IP_PROTO_UDP (17) | |
182 | #define IPTOS_ECN_MASK 0x03 | |
183 | #define IPTOS_ECN(x) ((x) & IPTOS_ECN_MASK) | |
184 | #define IPTOS_ECN_CE 0x03 | |
185 | #define IP6_ECN_MASK 0xC0 | |
186 | #define IP6_ECN(x) ((x) & IP6_ECN_MASK) | |
187 | #define IP6_ECN_CE 0xC0 | |
188 | #define IP4_DONT_FRAGMENT_FLAG (1 << 14) | |
189 | ||
190 | #define IS_SPECIAL_VLAN_ID(x) \ | |
191 | (((x) == 0) || ((x) == 0xFFF)) | |
192 | ||
193 | #define ETH_MAX_L2_HDR_LEN \ | |
194 | (sizeof(struct eth_header) + 2 * sizeof(struct vlan_header)) | |
195 | ||
196 | #define ETH_MAX_IP4_HDR_LEN (60) | |
197 | #define ETH_MAX_IP_DGRAM_LEN (0xFFFF) | |
198 | ||
199 | #define IP_FRAG_UNIT_SIZE (8) | |
200 | #define IP_FRAG_ALIGN_SIZE(x) ((x) & ~0x7) | |
201 | #define IP_RF 0x8000 /* reserved fragment flag */ | |
202 | #define IP_DF 0x4000 /* don't fragment flag */ | |
203 | #define IP_MF 0x2000 /* more fragments flag */ | |
204 | #define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ | |
205 | ||
206 | #define IP6_EXT_GRANULARITY (8) /* Size granularity for | |
207 | IPv6 extension headers */ | |
208 | ||
209 | /* IP6 extension header types */ | |
210 | #define IP6_HOP_BY_HOP (0) | |
211 | #define IP6_ROUTING (43) | |
212 | #define IP6_FRAGMENT (44) | |
213 | #define IP6_ESP (50) | |
214 | #define IP6_AUTHENTICATION (51) | |
215 | #define IP6_NONE (59) | |
216 | #define IP6_DESTINATON (60) | |
217 | #define IP6_MOBILITY (135) | |
218 | ||
219 | static inline int is_multicast_ether_addr(const uint8_t *addr) | |
220 | { | |
221 | return 0x01 & addr[0]; | |
222 | } | |
223 | ||
224 | static inline int is_broadcast_ether_addr(const uint8_t *addr) | |
225 | { | |
226 | return (addr[0] & addr[1] & addr[2] & addr[3] & addr[4] & addr[5]) == 0xff; | |
227 | } | |
228 | ||
229 | static inline int is_unicast_ether_addr(const uint8_t *addr) | |
230 | { | |
231 | return !is_multicast_ether_addr(addr); | |
232 | } | |
233 | ||
234 | typedef enum { | |
235 | ETH_PKT_UCAST = 0xAABBCC00, | |
236 | ETH_PKT_BCAST, | |
237 | ETH_PKT_MCAST | |
238 | } eth_pkt_types_e; | |
239 | ||
240 | static inline eth_pkt_types_e | |
241 | get_eth_packet_type(const struct eth_header *ehdr) | |
242 | { | |
243 | if (is_broadcast_ether_addr(ehdr->h_dest)) { | |
244 | return ETH_PKT_BCAST; | |
245 | } else if (is_multicast_ether_addr(ehdr->h_dest)) { | |
246 | return ETH_PKT_MCAST; | |
247 | } else { /* unicast */ | |
248 | return ETH_PKT_UCAST; | |
249 | } | |
250 | } | |
251 | ||
252 | static inline uint32_t | |
253 | eth_get_l2_hdr_length(const void *p) | |
254 | { | |
255 | uint16_t proto = be16_to_cpu(PKT_GET_ETH_HDR(p)->h_proto); | |
256 | struct vlan_header *hvlan = PKT_GET_VLAN_HDR(p); | |
257 | switch (proto) { | |
258 | case ETH_P_VLAN: | |
259 | return sizeof(struct eth_header) + sizeof(struct vlan_header); | |
260 | case ETH_P_DVLAN: | |
261 | if (hvlan->h_proto == ETH_P_VLAN) { | |
262 | return sizeof(struct eth_header) + 2 * sizeof(struct vlan_header); | |
263 | } else { | |
264 | return sizeof(struct eth_header) + sizeof(struct vlan_header); | |
265 | } | |
266 | default: | |
267 | return sizeof(struct eth_header); | |
268 | } | |
269 | } | |
270 | ||
271 | static inline uint16_t | |
272 | eth_get_pkt_tci(const void *p) | |
273 | { | |
274 | uint16_t proto = be16_to_cpu(PKT_GET_ETH_HDR(p)->h_proto); | |
275 | struct vlan_header *hvlan = PKT_GET_VLAN_HDR(p); | |
276 | switch (proto) { | |
277 | case ETH_P_VLAN: | |
278 | case ETH_P_DVLAN: | |
279 | return be16_to_cpu(hvlan->h_tci); | |
280 | default: | |
281 | return 0; | |
282 | } | |
283 | } | |
284 | ||
285 | static inline bool | |
286 | eth_strip_vlan(const void *p, uint8_t *new_ehdr_buf, | |
287 | uint16_t *payload_offset, uint16_t *tci) | |
288 | { | |
289 | uint16_t proto = be16_to_cpu(PKT_GET_ETH_HDR(p)->h_proto); | |
290 | struct vlan_header *hvlan = PKT_GET_VLAN_HDR(p); | |
291 | struct eth_header *new_ehdr = (struct eth_header *) new_ehdr_buf; | |
292 | ||
293 | switch (proto) { | |
294 | case ETH_P_VLAN: | |
295 | case ETH_P_DVLAN: | |
296 | memcpy(new_ehdr->h_source, PKT_GET_ETH_HDR(p)->h_source, ETH_ALEN); | |
297 | memcpy(new_ehdr->h_dest, PKT_GET_ETH_HDR(p)->h_dest, ETH_ALEN); | |
298 | new_ehdr->h_proto = hvlan->h_proto; | |
299 | *tci = be16_to_cpu(hvlan->h_tci); | |
300 | *payload_offset = | |
301 | sizeof(struct eth_header) + sizeof(struct vlan_header); | |
302 | if (be16_to_cpu(new_ehdr->h_proto) == ETH_P_VLAN) { | |
303 | memcpy(PKT_GET_VLAN_HDR(new_ehdr), | |
304 | PKT_GET_DVLAN_HDR(p), | |
305 | sizeof(struct vlan_header)); | |
306 | *payload_offset += sizeof(struct vlan_header); | |
307 | } | |
308 | return true; | |
309 | default: | |
310 | return false; | |
311 | } | |
312 | } | |
313 | ||
314 | static inline uint16_t | |
315 | eth_get_l3_proto(const void *l2hdr, size_t l2hdr_len) | |
316 | { | |
317 | uint8_t *proto_ptr = (uint8_t *) l2hdr + l2hdr_len - sizeof(uint16_t); | |
318 | return be16_to_cpup((uint16_t *)proto_ptr); | |
319 | } | |
320 | ||
321 | void eth_setup_vlan_headers(struct eth_header *ehdr, uint16_t vlan_tag, | |
322 | bool *is_new); | |
323 | ||
324 | uint8_t eth_get_gso_type(uint16_t l3_proto, uint8_t *l3_hdr, uint8_t l4proto); | |
325 | ||
326 | void eth_get_protocols(const uint8_t *headers, | |
327 | uint32_t hdr_length, | |
328 | bool *isip4, bool *isip6, | |
329 | bool *isudp, bool *istcp); | |
330 | ||
331 | void eth_setup_ip4_fragmentation(const void *l2hdr, size_t l2hdr_len, | |
332 | void *l3hdr, size_t l3hdr_len, | |
333 | size_t l3payload_len, | |
334 | size_t frag_offset, bool more_frags); | |
335 | ||
336 | void | |
337 | eth_fix_ip4_checksum(void *l3hdr, size_t l3hdr_len); | |
338 | ||
339 | uint32_t | |
340 | eth_calc_pseudo_hdr_csum(struct ip_header *iphdr, uint16_t csl); | |
341 | ||
342 | bool | |
343 | eth_parse_ipv6_hdr(struct iovec *pkt, int pkt_frags, | |
344 | size_t ip6hdr_off, uint8_t *l4proto, | |
345 | size_t *full_hdr_len); | |
346 | ||
347 | #endif |