diff options
Diffstat (limited to 'net/eth.c')
| -rw-r--r-- | net/eth.c | 100 |
1 files changed, 53 insertions, 47 deletions
diff --git a/net/eth.c b/net/eth.c index 70bcd8e355..649e66bb1f 100644 --- a/net/eth.c +++ b/net/eth.c @@ -21,26 +21,16 @@ #include "net/checksum.h" #include "net/tap.h" -void eth_setup_vlan_headers_ex(struct eth_header *ehdr, uint16_t vlan_tag, - uint16_t vlan_ethtype, bool *is_new) +void eth_setup_vlan_headers(struct eth_header *ehdr, size_t *ehdr_size, + uint16_t vlan_tag, uint16_t vlan_ethtype) { struct vlan_header *vhdr = PKT_GET_VLAN_HDR(ehdr); - switch (be16_to_cpu(ehdr->h_proto)) { - case ETH_P_VLAN: - case ETH_P_DVLAN: - /* vlan hdr exists */ - *is_new = false; - break; - - default: - /* No VLAN header, put a new one */ - vhdr->h_proto = ehdr->h_proto; - ehdr->h_proto = cpu_to_be16(vlan_ethtype); - *is_new = true; - break; - } + memmove(vhdr + 1, vhdr, *ehdr_size - ETH_HLEN); vhdr->h_tci = cpu_to_be16(vlan_tag); + vhdr->h_proto = ehdr->h_proto; + ehdr->h_proto = cpu_to_be16(vlan_ethtype); + *ehdr_size += sizeof(*vhdr); } uint8_t @@ -136,7 +126,7 @@ _eth_tcp_has_data(bool is_ip4, return l4len > TCP_HEADER_DATA_OFFSET(tcp); } -void eth_get_protocols(const struct iovec *iov, int iovcnt, +void eth_get_protocols(const struct iovec *iov, size_t iovcnt, size_t iovoff, bool *hasip4, bool *hasip6, size_t *l3hdr_off, size_t *l4hdr_off, @@ -147,26 +137,24 @@ void eth_get_protocols(const struct iovec *iov, int iovcnt, { int proto; bool fragment = false; - size_t l2hdr_len = eth_get_l2_hdr_length_iov(iov, iovcnt); size_t input_size = iov_size(iov, iovcnt); size_t copied; uint8_t ip_p; *hasip4 = *hasip6 = false; + *l3hdr_off = iovoff + eth_get_l2_hdr_length_iov(iov, iovcnt, iovoff); l4hdr_info->proto = ETH_L4_HDR_PROTO_INVALID; - proto = eth_get_l3_proto(iov, iovcnt, l2hdr_len); - - *l3hdr_off = l2hdr_len; + proto = eth_get_l3_proto(iov, iovcnt, *l3hdr_off); if (proto == ETH_P_IP) { struct ip_header *iphdr = &ip4hdr_info->ip4_hdr; - if (input_size < l2hdr_len) { + if (input_size < *l3hdr_off) { return; } - copied = iov_to_buf(iov, iovcnt, l2hdr_len, iphdr, sizeof(*iphdr)); + copied = iov_to_buf(iov, iovcnt, *l3hdr_off, iphdr, sizeof(*iphdr)); if (copied < sizeof(*iphdr) || IP_HEADER_VERSION(iphdr) != IP_HEADER_VERSION_4) { return; @@ -175,17 +163,17 @@ void eth_get_protocols(const struct iovec *iov, int iovcnt, *hasip4 = true; ip_p = iphdr->ip_p; ip4hdr_info->fragment = IP4_IS_FRAGMENT(iphdr); - *l4hdr_off = l2hdr_len + IP_HDR_GET_LEN(iphdr); + *l4hdr_off = *l3hdr_off + IP_HDR_GET_LEN(iphdr); fragment = ip4hdr_info->fragment; } else if (proto == ETH_P_IPV6) { - if (!eth_parse_ipv6_hdr(iov, iovcnt, l2hdr_len, ip6hdr_info)) { + if (!eth_parse_ipv6_hdr(iov, iovcnt, *l3hdr_off, ip6hdr_info)) { return; } *hasip6 = true; ip_p = ip6hdr_info->l4proto; - *l4hdr_off = l2hdr_len + ip6hdr_info->full_hdr_len; + *l4hdr_off = *l3hdr_off + ip6hdr_info->full_hdr_len; fragment = ip6hdr_info->fragment; } else { return; @@ -223,16 +211,20 @@ void eth_get_protocols(const struct iovec *iov, int iovcnt, *l5hdr_off = *l4hdr_off + sizeof(l4hdr_info->hdr.udp); } break; + + case IP_PROTO_SCTP: + l4hdr_info->proto = ETH_L4_HDR_PROTO_SCTP; + break; } } size_t eth_strip_vlan(const struct iovec *iov, int iovcnt, size_t iovoff, - uint8_t *new_ehdr_buf, + void *new_ehdr_buf, uint16_t *payload_offset, uint16_t *tci) { struct vlan_header vlan_hdr; - struct eth_header *new_ehdr = (struct eth_header *) new_ehdr_buf; + struct eth_header *new_ehdr = new_ehdr_buf; size_t copied = iov_to_buf(iov, iovcnt, iovoff, new_ehdr, sizeof(*new_ehdr)); @@ -277,36 +269,50 @@ eth_strip_vlan(const struct iovec *iov, int iovcnt, size_t iovoff, } size_t -eth_strip_vlan_ex(const struct iovec *iov, int iovcnt, size_t iovoff, - uint16_t vet, uint8_t *new_ehdr_buf, +eth_strip_vlan_ex(const struct iovec *iov, int iovcnt, size_t iovoff, int index, + uint16_t vet, uint16_t vet_ext, void *new_ehdr_buf, uint16_t *payload_offset, uint16_t *tci) { struct vlan_header vlan_hdr; - struct eth_header *new_ehdr = (struct eth_header *) new_ehdr_buf; - - size_t copied = iov_to_buf(iov, iovcnt, iovoff, - new_ehdr, sizeof(*new_ehdr)); - - if (copied < sizeof(*new_ehdr)) { - return 0; - } + uint16_t *new_ehdr_proto; + size_t new_ehdr_size; + size_t copied; - if (be16_to_cpu(new_ehdr->h_proto) == vet) { - copied = iov_to_buf(iov, iovcnt, iovoff + sizeof(*new_ehdr), - &vlan_hdr, sizeof(vlan_hdr)); + switch (index) { + case 0: + new_ehdr_proto = &PKT_GET_ETH_HDR(new_ehdr_buf)->h_proto; + new_ehdr_size = sizeof(struct eth_header); + copied = iov_to_buf(iov, iovcnt, iovoff, new_ehdr_buf, new_ehdr_size); + break; - if (copied < sizeof(vlan_hdr)) { + case 1: + new_ehdr_proto = &PKT_GET_VLAN_HDR(new_ehdr_buf)->h_proto; + new_ehdr_size = sizeof(struct eth_header) + sizeof(struct vlan_header); + copied = iov_to_buf(iov, iovcnt, iovoff, new_ehdr_buf, new_ehdr_size); + if (be16_to_cpu(PKT_GET_ETH_HDR(new_ehdr_buf)->h_proto) != vet_ext) { return 0; } + break; - new_ehdr->h_proto = vlan_hdr.h_proto; + default: + return 0; + } - *tci = be16_to_cpu(vlan_hdr.h_tci); - *payload_offset = iovoff + sizeof(*new_ehdr) + sizeof(vlan_hdr); - return sizeof(struct eth_header); + if (copied < new_ehdr_size || be16_to_cpu(*new_ehdr_proto) != vet) { + return 0; } - return 0; + copied = iov_to_buf(iov, iovcnt, iovoff + new_ehdr_size, + &vlan_hdr, sizeof(vlan_hdr)); + if (copied < sizeof(vlan_hdr)) { + return 0; + } + + *new_ehdr_proto = vlan_hdr.h_proto; + *payload_offset = iovoff + new_ehdr_size + sizeof(vlan_hdr); + *tci = be16_to_cpu(vlan_hdr.h_tci); + + return new_ehdr_size; } void |