#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
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,
{
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;
*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;
*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));
}
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;
+ }
+
+ copied = iov_to_buf(iov, iovcnt, iovoff + new_ehdr_size,
+ &vlan_hdr, sizeof(vlan_hdr));
+ if (copied < sizeof(vlan_hdr)) {
+ return 0;
}
- 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
}
if (opthdr.type == IP6_OPT_HOME) {
- size_t input_size = iov_size(pkt, pkt_frags);
-
if (input_size < opt_offset + sizeof(opthdr)) {
return false;
}