xref: /openbmc/qemu/include/net/eth.h (revision 3f4ad55ea28f75804d999cd3e1169c188bde052a)
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