175020a70SDmitry Fleytman /*
275020a70SDmitry Fleytman * QEMU network structures definitions and helper functions
375020a70SDmitry Fleytman *
475020a70SDmitry Fleytman * Copyright (c) 2012 Ravello Systems LTD (http://ravellosystems.com)
575020a70SDmitry Fleytman *
675020a70SDmitry Fleytman * Developed by Daynix Computing LTD (http://www.daynix.com)
775020a70SDmitry Fleytman *
875020a70SDmitry Fleytman * Portions developed by Free Software Foundation, Inc
975020a70SDmitry Fleytman * Copyright (C) 1991-1997, 2001, 2003, 2006 Free Software Foundation, Inc.
1075020a70SDmitry Fleytman * See netinet/ip6.h and netinet/in.h (GNU C Library)
1175020a70SDmitry Fleytman *
1275020a70SDmitry Fleytman * Portions developed by Igor Kovalenko
1375020a70SDmitry Fleytman * Copyright (c) 2006 Igor Kovalenko
1475020a70SDmitry Fleytman * See hw/rtl8139.c (QEMU)
1575020a70SDmitry Fleytman *
1675020a70SDmitry Fleytman * Authors:
1775020a70SDmitry Fleytman * Dmitry Fleytman <dmitry@daynix.com>
1875020a70SDmitry Fleytman * Tamir Shomer <tamirs@daynix.com>
1975020a70SDmitry Fleytman * Yan Vugenfirer <yan@daynix.com>
2075020a70SDmitry Fleytman *
2175020a70SDmitry Fleytman * This work is licensed under the terms of the GNU GPL, version 2 or later.
2275020a70SDmitry Fleytman * See the COPYING file in the top-level directory.
2375020a70SDmitry Fleytman *
2475020a70SDmitry Fleytman */
2575020a70SDmitry Fleytman
2675020a70SDmitry Fleytman #ifndef QEMU_ETH_H
2775020a70SDmitry Fleytman #define QEMU_ETH_H
2875020a70SDmitry Fleytman
2975020a70SDmitry Fleytman #include "qemu/bswap.h"
3075020a70SDmitry Fleytman #include "qemu/iov.h"
3175020a70SDmitry Fleytman
3275020a70SDmitry Fleytman #define ETH_ALEN 6
339c7ffe26SDr. David Alan Gilbert #define ETH_HLEN 14
34af774513SBin Meng #define ETH_ZLEN 60 /* Min. octets in frame without FCS */
3574349514SAkihiko Odaki #define ETH_FCS_LEN 4
3674349514SAkihiko Odaki #define ETH_MTU 1500
3775020a70SDmitry Fleytman
3875020a70SDmitry Fleytman struct eth_header {
3975020a70SDmitry Fleytman uint8_t h_dest[ETH_ALEN]; /* destination eth addr */
4075020a70SDmitry Fleytman uint8_t h_source[ETH_ALEN]; /* source ether addr */
4175020a70SDmitry Fleytman uint16_t h_proto; /* packet type ID field */
4275020a70SDmitry Fleytman };
4375020a70SDmitry Fleytman
4475020a70SDmitry Fleytman struct vlan_header {
4575020a70SDmitry Fleytman uint16_t h_tci; /* priority and VLAN ID */
4675020a70SDmitry Fleytman uint16_t h_proto; /* encapsulated protocol */
4775020a70SDmitry Fleytman };
4875020a70SDmitry Fleytman
4975020a70SDmitry Fleytman struct ip_header {
5075020a70SDmitry Fleytman uint8_t ip_ver_len; /* version and header length */
5175020a70SDmitry Fleytman uint8_t ip_tos; /* type of service */
5275020a70SDmitry Fleytman uint16_t ip_len; /* total length */
5375020a70SDmitry Fleytman uint16_t ip_id; /* identification */
5475020a70SDmitry Fleytman uint16_t ip_off; /* fragment offset field */
5575020a70SDmitry Fleytman uint8_t ip_ttl; /* time to live */
5675020a70SDmitry Fleytman uint8_t ip_p; /* protocol */
5775020a70SDmitry Fleytman uint16_t ip_sum; /* checksum */
5875020a70SDmitry Fleytman uint32_t ip_src, ip_dst; /* source and destination address */
59*f8b94b4cSPeter Maydell } QEMU_PACKED;
6075020a70SDmitry Fleytman
6175020a70SDmitry Fleytman typedef struct tcp_header {
6275020a70SDmitry Fleytman uint16_t th_sport; /* source port */
6375020a70SDmitry Fleytman uint16_t th_dport; /* destination port */
6475020a70SDmitry Fleytman uint32_t th_seq; /* sequence number */
6575020a70SDmitry Fleytman uint32_t th_ack; /* acknowledgment number */
6675020a70SDmitry Fleytman uint16_t th_offset_flags; /* data offset, reserved 6 bits, */
6775020a70SDmitry Fleytman /* TCP protocol flags */
6875020a70SDmitry Fleytman uint16_t th_win; /* window */
6975020a70SDmitry Fleytman uint16_t th_sum; /* checksum */
7075020a70SDmitry Fleytman uint16_t th_urp; /* urgent pointer */
7175020a70SDmitry Fleytman } tcp_header;
7275020a70SDmitry Fleytman
7366409b7cSDmitry Fleytman #define TCP_FLAGS_ONLY(flags) ((flags) & 0x3f)
7466409b7cSDmitry Fleytman
7566409b7cSDmitry Fleytman #define TCP_HEADER_FLAGS(tcp) \
7666409b7cSDmitry Fleytman TCP_FLAGS_ONLY(be16_to_cpu((tcp)->th_offset_flags))
7766409b7cSDmitry Fleytman
78eb700029SDmitry Fleytman #define TCP_FLAG_ACK 0x10
79eb700029SDmitry Fleytman
8066409b7cSDmitry Fleytman #define TCP_HEADER_DATA_OFFSET(tcp) \
8166409b7cSDmitry Fleytman (((be16_to_cpu((tcp)->th_offset_flags) >> 12) & 0xf) << 2)
8266409b7cSDmitry Fleytman
8375020a70SDmitry Fleytman typedef struct udp_header {
8475020a70SDmitry Fleytman uint16_t uh_sport; /* source port */
8575020a70SDmitry Fleytman uint16_t uh_dport; /* destination port */
8675020a70SDmitry Fleytman uint16_t uh_ulen; /* udp length */
8775020a70SDmitry Fleytman uint16_t uh_sum; /* udp checksum */
8875020a70SDmitry Fleytman } udp_header;
8975020a70SDmitry Fleytman
9075020a70SDmitry Fleytman typedef struct ip_pseudo_header {
9175020a70SDmitry Fleytman uint32_t ip_src;
9275020a70SDmitry Fleytman uint32_t ip_dst;
9375020a70SDmitry Fleytman uint8_t zeros;
9475020a70SDmitry Fleytman uint8_t ip_proto;
9575020a70SDmitry Fleytman uint16_t ip_payload;
9675020a70SDmitry Fleytman } ip_pseudo_header;
9775020a70SDmitry Fleytman
9875020a70SDmitry Fleytman /* IPv6 address */
99d60b20cfSDmitry Krivenok struct in6_address {
10075020a70SDmitry Fleytman union {
10175020a70SDmitry Fleytman uint8_t __u6_addr8[16];
10275020a70SDmitry Fleytman } __in6_u;
10375020a70SDmitry Fleytman };
10475020a70SDmitry Fleytman
10575020a70SDmitry Fleytman struct ip6_header {
10675020a70SDmitry Fleytman union {
10775020a70SDmitry Fleytman struct ip6_hdrctl {
10875020a70SDmitry Fleytman uint32_t ip6_un1_flow; /* 4 bits version, 8 bits TC,
10975020a70SDmitry Fleytman 20 bits flow-ID */
11075020a70SDmitry Fleytman uint16_t ip6_un1_plen; /* payload length */
11175020a70SDmitry Fleytman uint8_t ip6_un1_nxt; /* next header */
11275020a70SDmitry Fleytman uint8_t ip6_un1_hlim; /* hop limit */
11375020a70SDmitry Fleytman } ip6_un1;
11475020a70SDmitry Fleytman uint8_t ip6_un2_vfc; /* 4 bits version, top 4 bits tclass */
11575020a70SDmitry Fleytman struct ip6_ecn_access {
11675020a70SDmitry Fleytman uint8_t ip6_un3_vfc; /* 4 bits version, top 4 bits tclass */
11775020a70SDmitry Fleytman uint8_t ip6_un3_ecn; /* 2 bits ECN, top 6 bits payload length */
11875020a70SDmitry Fleytman } ip6_un3;
11975020a70SDmitry Fleytman } ip6_ctlun;
120d60b20cfSDmitry Krivenok struct in6_address ip6_src; /* source address */
121d60b20cfSDmitry Krivenok struct in6_address ip6_dst; /* destination address */
12275020a70SDmitry Fleytman };
12375020a70SDmitry Fleytman
124eb700029SDmitry Fleytman typedef struct ip6_pseudo_header {
125eb700029SDmitry Fleytman struct in6_address ip6_src;
126eb700029SDmitry Fleytman struct in6_address ip6_dst;
127eb700029SDmitry Fleytman uint32_t len;
128eb700029SDmitry Fleytman uint8_t zero[3];
129eb700029SDmitry Fleytman uint8_t next_hdr;
130eb700029SDmitry Fleytman } ip6_pseudo_header;
131eb700029SDmitry Fleytman
13275020a70SDmitry Fleytman struct ip6_ext_hdr {
13375020a70SDmitry Fleytman uint8_t ip6r_nxt; /* next header */
13475020a70SDmitry Fleytman uint8_t ip6r_len; /* length in units of 8 octets */
13575020a70SDmitry Fleytman };
13675020a70SDmitry Fleytman
137eb700029SDmitry Fleytman struct ip6_ext_hdr_routing {
138eb700029SDmitry Fleytman uint8_t nxt;
139eb700029SDmitry Fleytman uint8_t len;
140eb700029SDmitry Fleytman uint8_t rtype;
141eb700029SDmitry Fleytman uint8_t segleft;
142eb700029SDmitry Fleytman uint8_t rsvd[4];
143eb700029SDmitry Fleytman };
144eb700029SDmitry Fleytman
145eb700029SDmitry Fleytman struct ip6_option_hdr {
146eb700029SDmitry Fleytman #define IP6_OPT_PAD1 (0x00)
147eb700029SDmitry Fleytman #define IP6_OPT_HOME (0xC9)
148eb700029SDmitry Fleytman uint8_t type;
149eb700029SDmitry Fleytman uint8_t len;
150eb700029SDmitry Fleytman };
151eb700029SDmitry Fleytman
15275020a70SDmitry Fleytman struct udp_hdr {
15375020a70SDmitry Fleytman uint16_t uh_sport; /* source port */
15475020a70SDmitry Fleytman uint16_t uh_dport; /* destination port */
15575020a70SDmitry Fleytman uint16_t uh_ulen; /* udp length */
15675020a70SDmitry Fleytman uint16_t uh_sum; /* udp checksum */
15775020a70SDmitry Fleytman };
15875020a70SDmitry Fleytman
15975020a70SDmitry Fleytman struct tcp_hdr {
16075020a70SDmitry Fleytman u_short th_sport; /* source port */
16175020a70SDmitry Fleytman u_short th_dport; /* destination port */
16275020a70SDmitry Fleytman uint32_t th_seq; /* sequence number */
16375020a70SDmitry Fleytman uint32_t th_ack; /* acknowledgment number */
164e03b5686SMarc-André Lureau #if HOST_BIG_ENDIAN
16575020a70SDmitry Fleytman u_char th_off : 4, /* data offset */
16675020a70SDmitry Fleytman th_x2:4; /* (unused) */
16775020a70SDmitry Fleytman #else
16875020a70SDmitry Fleytman u_char th_x2 : 4, /* (unused) */
16975020a70SDmitry Fleytman th_off:4; /* data offset */
17075020a70SDmitry Fleytman #endif
17175020a70SDmitry Fleytman
17275020a70SDmitry Fleytman #define TH_ELN 0x1 /* explicit loss notification */
17375020a70SDmitry Fleytman #define TH_ECN 0x2 /* explicit congestion notification */
17475020a70SDmitry Fleytman #define TH_FS 0x4 /* fast start */
17575020a70SDmitry Fleytman
17675020a70SDmitry Fleytman u_char th_flags;
17775020a70SDmitry Fleytman #define TH_FIN 0x01
17875020a70SDmitry Fleytman #define TH_SYN 0x02
17975020a70SDmitry Fleytman #define TH_RST 0x04
18075020a70SDmitry Fleytman #define TH_PUSH 0x08
18175020a70SDmitry Fleytman #define TH_ACK 0x10
18275020a70SDmitry Fleytman #define TH_URG 0x20
1832974e916SYuri Benditovich #define TH_ECE 0x40
1842974e916SYuri Benditovich #define TH_CWR 0x80
18575020a70SDmitry Fleytman u_short th_win; /* window */
18675020a70SDmitry Fleytman u_short th_sum; /* checksum */
18775020a70SDmitry Fleytman u_short th_urp; /* urgent pointer */
18875020a70SDmitry Fleytman };
18975020a70SDmitry Fleytman
19075020a70SDmitry Fleytman #define ip6_nxt ip6_ctlun.ip6_un1.ip6_un1_nxt
19175020a70SDmitry Fleytman #define ip6_ecn_acc ip6_ctlun.ip6_un3.ip6_un3_ecn
192e219d309SAndrew #define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen
19375020a70SDmitry Fleytman
19475020a70SDmitry Fleytman #define PKT_GET_ETH_HDR(p) \
19575020a70SDmitry Fleytman ((struct eth_header *)(p))
19675020a70SDmitry Fleytman #define PKT_GET_VLAN_HDR(p) \
19775020a70SDmitry Fleytman ((struct vlan_header *) (((uint8_t *)(p)) + sizeof(struct eth_header)))
19875020a70SDmitry Fleytman #define PKT_GET_DVLAN_HDR(p) \
19975020a70SDmitry Fleytman (PKT_GET_VLAN_HDR(p) + 1)
20075020a70SDmitry Fleytman #define PKT_GET_IP_HDR(p) \
20175020a70SDmitry Fleytman ((struct ip_header *)(((uint8_t *)(p)) + eth_get_l2_hdr_length(p)))
20275020a70SDmitry Fleytman #define IP_HDR_GET_LEN(p) \
2034f51e1d3SMarc-André Lureau ((ldub_p(p + offsetof(struct ip_header, ip_ver_len)) & 0x0F) << 2)
2044f51e1d3SMarc-André Lureau #define IP_HDR_GET_P(p) \
2054f51e1d3SMarc-André Lureau (ldub_p(p + offsetof(struct ip_header, ip_p)))
20675020a70SDmitry Fleytman #define PKT_GET_IP_HDR_LEN(p) \
20775020a70SDmitry Fleytman (IP_HDR_GET_LEN(PKT_GET_IP_HDR(p)))
20875020a70SDmitry Fleytman #define PKT_GET_IP6_HDR(p) \
20975020a70SDmitry Fleytman ((struct ip6_header *) (((uint8_t *)(p)) + eth_get_l2_hdr_length(p)))
21075020a70SDmitry Fleytman #define IP_HEADER_VERSION(ip) \
211eb700029SDmitry Fleytman (((ip)->ip_ver_len >> 4) & 0xf)
212eb700029SDmitry Fleytman #define IP4_IS_FRAGMENT(ip) \
213eb700029SDmitry Fleytman ((be16_to_cpu((ip)->ip_off) & (IP_OFFMASK | IP_MF)) != 0)
21475020a70SDmitry Fleytman
2159c7ffe26SDr. David Alan Gilbert #define ETH_P_IP (0x0800) /* Internet Protocol packet */
2169c7ffe26SDr. David Alan Gilbert #define ETH_P_ARP (0x0806) /* Address Resolution packet */
21775020a70SDmitry Fleytman #define ETH_P_IPV6 (0x86dd)
21875020a70SDmitry Fleytman #define ETH_P_VLAN (0x8100)
21975020a70SDmitry Fleytman #define ETH_P_DVLAN (0x88a8)
22047bb83caSCédric Le Goater #define ETH_P_NCSI (0x88f8)
221eb700029SDmitry Fleytman #define ETH_P_UNKNOWN (0xffff)
22275020a70SDmitry Fleytman #define VLAN_VID_MASK 0x0fff
22375020a70SDmitry Fleytman #define IP_HEADER_VERSION_4 (4)
22475020a70SDmitry Fleytman #define IP_HEADER_VERSION_6 (6)
22575020a70SDmitry Fleytman #define IP_PROTO_TCP (6)
22675020a70SDmitry Fleytman #define IP_PROTO_UDP (17)
227907209e3SAkihiko Odaki #define IP_PROTO_SCTP (132)
22875020a70SDmitry Fleytman #define IPTOS_ECN_MASK 0x03
22975020a70SDmitry Fleytman #define IPTOS_ECN(x) ((x) & IPTOS_ECN_MASK)
23075020a70SDmitry Fleytman #define IPTOS_ECN_CE 0x03
23175020a70SDmitry Fleytman #define IP6_ECN_MASK 0xC0
23275020a70SDmitry Fleytman #define IP6_ECN(x) ((x) & IP6_ECN_MASK)
23375020a70SDmitry Fleytman #define IP6_ECN_CE 0xC0
23475020a70SDmitry Fleytman #define IP4_DONT_FRAGMENT_FLAG (1 << 14)
23575020a70SDmitry Fleytman
23675020a70SDmitry Fleytman #define IS_SPECIAL_VLAN_ID(x) \
23775020a70SDmitry Fleytman (((x) == 0) || ((x) == 0xFFF))
23875020a70SDmitry Fleytman
23975020a70SDmitry Fleytman #define ETH_MAX_L2_HDR_LEN \
24075020a70SDmitry Fleytman (sizeof(struct eth_header) + 2 * sizeof(struct vlan_header))
24175020a70SDmitry Fleytman
24275020a70SDmitry Fleytman #define ETH_MAX_IP4_HDR_LEN (60)
24375020a70SDmitry Fleytman #define ETH_MAX_IP_DGRAM_LEN (0xFFFF)
24475020a70SDmitry Fleytman
24575020a70SDmitry Fleytman #define IP_FRAG_UNIT_SIZE (8)
24675020a70SDmitry Fleytman #define IP_FRAG_ALIGN_SIZE(x) ((x) & ~0x7)
24775020a70SDmitry Fleytman #define IP_RF 0x8000 /* reserved fragment flag */
24875020a70SDmitry Fleytman #define IP_DF 0x4000 /* don't fragment flag */
24975020a70SDmitry Fleytman #define IP_MF 0x2000 /* more fragments flag */
25075020a70SDmitry Fleytman #define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
25175020a70SDmitry Fleytman
25275020a70SDmitry Fleytman #define IP6_EXT_GRANULARITY (8) /* Size granularity for
25375020a70SDmitry Fleytman IPv6 extension headers */
25475020a70SDmitry Fleytman
25575020a70SDmitry Fleytman /* IP6 extension header types */
25675020a70SDmitry Fleytman #define IP6_HOP_BY_HOP (0)
25775020a70SDmitry Fleytman #define IP6_ROUTING (43)
25875020a70SDmitry Fleytman #define IP6_FRAGMENT (44)
25975020a70SDmitry Fleytman #define IP6_ESP (50)
26075020a70SDmitry Fleytman #define IP6_AUTHENTICATION (51)
26175020a70SDmitry Fleytman #define IP6_NONE (59)
26275020a70SDmitry Fleytman #define IP6_DESTINATON (60)
26375020a70SDmitry Fleytman #define IP6_MOBILITY (135)
26475020a70SDmitry Fleytman
is_multicast_ether_addr(const uint8_t * addr)26575020a70SDmitry Fleytman static inline int is_multicast_ether_addr(const uint8_t *addr)
26675020a70SDmitry Fleytman {
26775020a70SDmitry Fleytman return 0x01 & addr[0];
26875020a70SDmitry Fleytman }
26975020a70SDmitry Fleytman
is_broadcast_ether_addr(const uint8_t * addr)27075020a70SDmitry Fleytman static inline int is_broadcast_ether_addr(const uint8_t *addr)
27175020a70SDmitry Fleytman {
27275020a70SDmitry Fleytman return (addr[0] & addr[1] & addr[2] & addr[3] & addr[4] & addr[5]) == 0xff;
27375020a70SDmitry Fleytman }
27475020a70SDmitry Fleytman
is_unicast_ether_addr(const uint8_t * addr)27575020a70SDmitry Fleytman static inline int is_unicast_ether_addr(const uint8_t *addr)
27675020a70SDmitry Fleytman {
27775020a70SDmitry Fleytman return !is_multicast_ether_addr(addr);
27875020a70SDmitry Fleytman }
27975020a70SDmitry Fleytman
28075020a70SDmitry Fleytman typedef enum {
28175020a70SDmitry Fleytman ETH_PKT_UCAST = 0xAABBCC00,
28275020a70SDmitry Fleytman ETH_PKT_BCAST,
28375020a70SDmitry Fleytman ETH_PKT_MCAST
28475020a70SDmitry Fleytman } eth_pkt_types_e;
28575020a70SDmitry Fleytman
28675020a70SDmitry Fleytman static inline eth_pkt_types_e
get_eth_packet_type(const struct eth_header * ehdr)28775020a70SDmitry Fleytman get_eth_packet_type(const struct eth_header *ehdr)
28875020a70SDmitry Fleytman {
28975020a70SDmitry Fleytman if (is_broadcast_ether_addr(ehdr->h_dest)) {
29075020a70SDmitry Fleytman return ETH_PKT_BCAST;
29175020a70SDmitry Fleytman } else if (is_multicast_ether_addr(ehdr->h_dest)) {
29275020a70SDmitry Fleytman return ETH_PKT_MCAST;
29375020a70SDmitry Fleytman } else { /* unicast */
29475020a70SDmitry Fleytman return ETH_PKT_UCAST;
29575020a70SDmitry Fleytman }
29675020a70SDmitry Fleytman }
29775020a70SDmitry Fleytman
29875020a70SDmitry Fleytman static inline uint32_t
eth_get_l2_hdr_length(const void * p)29975020a70SDmitry Fleytman eth_get_l2_hdr_length(const void *p)
30075020a70SDmitry Fleytman {
30175020a70SDmitry Fleytman uint16_t proto = be16_to_cpu(PKT_GET_ETH_HDR(p)->h_proto);
30275020a70SDmitry Fleytman struct vlan_header *hvlan = PKT_GET_VLAN_HDR(p);
30375020a70SDmitry Fleytman switch (proto) {
30475020a70SDmitry Fleytman case ETH_P_VLAN:
30575020a70SDmitry Fleytman return sizeof(struct eth_header) + sizeof(struct vlan_header);
30675020a70SDmitry Fleytman case ETH_P_DVLAN:
307eb700029SDmitry Fleytman if (be16_to_cpu(hvlan->h_proto) == ETH_P_VLAN) {
30875020a70SDmitry Fleytman return sizeof(struct eth_header) + 2 * sizeof(struct vlan_header);
30975020a70SDmitry Fleytman } else {
31075020a70SDmitry Fleytman return sizeof(struct eth_header) + sizeof(struct vlan_header);
31175020a70SDmitry Fleytman }
31275020a70SDmitry Fleytman default:
31375020a70SDmitry Fleytman return sizeof(struct eth_header);
31475020a70SDmitry Fleytman }
31575020a70SDmitry Fleytman }
31675020a70SDmitry Fleytman
317eb700029SDmitry Fleytman static inline uint32_t
eth_get_l2_hdr_length_iov(const struct iovec * iov,size_t iovcnt,size_t iovoff)3182f0fa232SAkihiko Odaki eth_get_l2_hdr_length_iov(const struct iovec *iov, size_t iovcnt, size_t iovoff)
319eb700029SDmitry Fleytman {
320eb700029SDmitry Fleytman uint8_t p[sizeof(struct eth_header) + sizeof(struct vlan_header)];
3212f0fa232SAkihiko Odaki size_t copied = iov_to_buf(iov, iovcnt, iovoff, p, ARRAY_SIZE(p));
322eb700029SDmitry Fleytman
323eb700029SDmitry Fleytman if (copied < ARRAY_SIZE(p)) {
324eb700029SDmitry Fleytman return copied;
325eb700029SDmitry Fleytman }
326eb700029SDmitry Fleytman
327eb700029SDmitry Fleytman return eth_get_l2_hdr_length(p);
328eb700029SDmitry Fleytman }
329eb700029SDmitry Fleytman
33075020a70SDmitry Fleytman static inline uint16_t
eth_get_pkt_tci(const void * p)33175020a70SDmitry Fleytman eth_get_pkt_tci(const void *p)
33275020a70SDmitry Fleytman {
33375020a70SDmitry Fleytman uint16_t proto = be16_to_cpu(PKT_GET_ETH_HDR(p)->h_proto);
33475020a70SDmitry Fleytman struct vlan_header *hvlan = PKT_GET_VLAN_HDR(p);
33575020a70SDmitry Fleytman switch (proto) {
33675020a70SDmitry Fleytman case ETH_P_VLAN:
33775020a70SDmitry Fleytman case ETH_P_DVLAN:
33875020a70SDmitry Fleytman return be16_to_cpu(hvlan->h_tci);
33975020a70SDmitry Fleytman default:
34075020a70SDmitry Fleytman return 0;
34175020a70SDmitry Fleytman }
34275020a70SDmitry Fleytman }
34375020a70SDmitry Fleytman
344566342c3SDmitry Fleytman size_t
345eb700029SDmitry Fleytman eth_strip_vlan(const struct iovec *iov, int iovcnt, size_t iovoff,
34685427bf3SAkihiko Odaki void *new_ehdr_buf,
347eb700029SDmitry Fleytman uint16_t *payload_offset, uint16_t *tci);
348eb700029SDmitry Fleytman
349566342c3SDmitry Fleytman size_t
3507e64a9caSAkihiko Odaki eth_strip_vlan_ex(const struct iovec *iov, int iovcnt, size_t iovoff, int index,
3517e64a9caSAkihiko Odaki uint16_t vet, uint16_t vet_ext, void *new_ehdr_buf,
352eb700029SDmitry Fleytman uint16_t *payload_offset, uint16_t *tci);
353eb700029SDmitry Fleytman
354eb700029SDmitry Fleytman uint16_t
355eb700029SDmitry Fleytman eth_get_l3_proto(const struct iovec *l2hdr_iov, int iovcnt, size_t l2hdr_len);
356eb700029SDmitry Fleytman
357aaa8a15cSAkihiko Odaki void eth_setup_vlan_headers(struct eth_header *ehdr, size_t *ehdr_size,
358aaa8a15cSAkihiko Odaki uint16_t vlan_tag, uint16_t vlan_ethtype);
359eb700029SDmitry Fleytman
36075020a70SDmitry Fleytman
36175020a70SDmitry Fleytman uint8_t eth_get_gso_type(uint16_t l3_proto, uint8_t *l3_hdr, uint8_t l4proto);
36275020a70SDmitry Fleytman
363eb700029SDmitry Fleytman typedef struct eth_ip6_hdr_info_st {
364eb700029SDmitry Fleytman uint8_t l4proto;
365eb700029SDmitry Fleytman size_t full_hdr_len;
366eb700029SDmitry Fleytman struct ip6_header ip6_hdr;
367eb700029SDmitry Fleytman bool has_ext_hdrs;
368eb700029SDmitry Fleytman bool rss_ex_src_valid;
369eb700029SDmitry Fleytman struct in6_address rss_ex_src;
370eb700029SDmitry Fleytman bool rss_ex_dst_valid;
371eb700029SDmitry Fleytman struct in6_address rss_ex_dst;
372eb700029SDmitry Fleytman bool fragment;
373eb700029SDmitry Fleytman } eth_ip6_hdr_info;
374eb700029SDmitry Fleytman
375eb700029SDmitry Fleytman typedef struct eth_ip4_hdr_info_st {
376eb700029SDmitry Fleytman struct ip_header ip4_hdr;
377eb700029SDmitry Fleytman bool fragment;
378eb700029SDmitry Fleytman } eth_ip4_hdr_info;
379eb700029SDmitry Fleytman
38065f474bbSAkihiko Odaki typedef enum EthL4HdrProto {
38165f474bbSAkihiko Odaki ETH_L4_HDR_PROTO_INVALID,
38265f474bbSAkihiko Odaki ETH_L4_HDR_PROTO_TCP,
383907209e3SAkihiko Odaki ETH_L4_HDR_PROTO_UDP,
384907209e3SAkihiko Odaki ETH_L4_HDR_PROTO_SCTP
38565f474bbSAkihiko Odaki } EthL4HdrProto;
38665f474bbSAkihiko Odaki
387eb700029SDmitry Fleytman typedef struct eth_l4_hdr_info_st {
388eb700029SDmitry Fleytman union {
389eb700029SDmitry Fleytman struct tcp_header tcp;
390eb700029SDmitry Fleytman struct udp_header udp;
391eb700029SDmitry Fleytman } hdr;
392eb700029SDmitry Fleytman
39365f474bbSAkihiko Odaki EthL4HdrProto proto;
394eb700029SDmitry Fleytman bool has_tcp_data;
395eb700029SDmitry Fleytman } eth_l4_hdr_info;
396eb700029SDmitry Fleytman
3972f0fa232SAkihiko Odaki void eth_get_protocols(const struct iovec *iov, size_t iovcnt, size_t iovoff,
39869ff5ef8SAkihiko Odaki bool *hasip4, bool *hasip6,
399eb700029SDmitry Fleytman size_t *l3hdr_off,
400eb700029SDmitry Fleytman size_t *l4hdr_off,
401eb700029SDmitry Fleytman size_t *l5hdr_off,
402eb700029SDmitry Fleytman eth_ip6_hdr_info *ip6hdr_info,
403eb700029SDmitry Fleytman eth_ip4_hdr_info *ip4hdr_info,
404eb700029SDmitry Fleytman eth_l4_hdr_info *l4hdr_info);
40575020a70SDmitry Fleytman
40675020a70SDmitry Fleytman void
40775020a70SDmitry Fleytman eth_fix_ip4_checksum(void *l3hdr, size_t l3hdr_len);
40875020a70SDmitry Fleytman
40975020a70SDmitry Fleytman uint32_t
410eb700029SDmitry Fleytman eth_calc_ip4_pseudo_hdr_csum(struct ip_header *iphdr,
411eb700029SDmitry Fleytman uint16_t csl,
412eb700029SDmitry Fleytman uint32_t *cso);
413eb700029SDmitry Fleytman
414eb700029SDmitry Fleytman uint32_t
415eb700029SDmitry Fleytman eth_calc_ip6_pseudo_hdr_csum(struct ip6_header *iphdr,
416eb700029SDmitry Fleytman uint16_t csl,
417eb700029SDmitry Fleytman uint8_t l4_proto,
418eb700029SDmitry Fleytman uint32_t *cso);
41975020a70SDmitry Fleytman
42075020a70SDmitry Fleytman bool
421eb700029SDmitry Fleytman eth_parse_ipv6_hdr(const struct iovec *pkt, int pkt_frags,
422eb700029SDmitry Fleytman size_t ip6hdr_off, eth_ip6_hdr_info *info);
42375020a70SDmitry Fleytman
424af774513SBin Meng /**
425af774513SBin Meng * eth_pad_short_frame - pad a short frame to the minimum Ethernet frame length
426af774513SBin Meng *
427af774513SBin Meng * If the Ethernet frame size is shorter than 60 bytes, it will be padded to
428af774513SBin Meng * 60 bytes at the address @padded_pkt.
429af774513SBin Meng *
430af774513SBin Meng * @padded_pkt: buffer address to hold the padded frame
431af774513SBin Meng * @padded_buflen: pointer holding length of @padded_pkt. If the frame is
432af774513SBin Meng * padded, the length will be updated to the padded one.
433af774513SBin Meng * @pkt: address to hold the original Ethernet frame
434af774513SBin Meng * @pkt_size: size of the original Ethernet frame
435af774513SBin Meng * @return true if the frame is padded, otherwise false
436af774513SBin Meng */
437af774513SBin Meng bool eth_pad_short_frame(uint8_t *padded_pkt, size_t *padded_buflen,
438af774513SBin Meng const void *pkt, size_t pkt_size);
439af774513SBin Meng
44075020a70SDmitry Fleytman #endif
441