+ if (is_tun && f->next_header == IP_PROTOCOL_GRE)
+ {
+ gre_header_t *gre;
+
+ b[0]->current_data = pd->current_data + adv;
+ b[0]->current_length = pd->current_length - adv - tail;
+
+ gre = vlib_buffer_get_current (b[0]);
+
+ vlib_buffer_advance (b[0], sizeof (*gre));
+
+ switch (clib_net_to_host_u16 (gre->protocol))
+ {
+ case GRE_PROTOCOL_teb:
+ vnet_update_l2_len (b[0]);
+ next[0] = ESP_DECRYPT_NEXT_L2_INPUT;
+ break;
+ case GRE_PROTOCOL_ip4:
+ next[0] = ESP_DECRYPT_NEXT_IP4_INPUT;
+ break;
+ case GRE_PROTOCOL_ip6:
+ next[0] = ESP_DECRYPT_NEXT_IP6_INPUT;
+ break;
+ default:
+ b[0]->error =
+ node->errors[ESP_DECRYPT_ERROR_UNSUP_PAYLOAD];
+ next[0] = ESP_DECRYPT_NEXT_DROP;
+ break;
+ }
+ }
+ else
+ {
+ next[0] = ESP_DECRYPT_NEXT_DROP;
+ b[0]->error = node->errors[ESP_DECRYPT_ERROR_UNSUP_PAYLOAD];
+ goto trace;
+ }
+ }
+ if (is_tun)
+ {
+ if (ipsec_sa_is_set_IS_PROTECT (sa0))
+ {
+ /*
+ * There are two encap possibilities
+ * 1) the tunnel and ths SA are prodiving encap, i.e. it's
+ * MAC | SA-IP | TUN-IP | ESP | PAYLOAD
+ * implying the SA is in tunnel mode (on a tunnel interface)
+ * 2) only the tunnel provides encap
+ * MAC | TUN-IP | ESP | PAYLOAD
+ * implying the SA is in transport mode.
+ *
+ * For 2) we need only strip the tunnel encap and we're good.
+ * since the tunnel and crypto ecnap (int the tun=protect
+ * object) are the same and we verified above that these match
+ * for 1) we need to strip the SA-IP outer headers, to
+ * reveal the tunnel IP and then check that this matches
+ * the configured tunnel.
+ */
+ const ipsec_tun_protect_t *itp;
+
+ itp = ipsec_tun_protect_get
+ (vnet_buffer (b[0])->ipsec.protect_index);
+
+ if (PREDICT_TRUE (f->next_header == IP_PROTOCOL_IP_IN_IP))
+ {
+ const ip4_header_t *ip4;
+
+ ip4 = vlib_buffer_get_current (b[0]);
+
+ if (!ip46_address_is_equal_v4 (&itp->itp_tun.src,
+ &ip4->dst_address) ||
+ !ip46_address_is_equal_v4 (&itp->itp_tun.dst,
+ &ip4->src_address))
+ {
+ next[0] = ESP_DECRYPT_NEXT_DROP;
+ b[0]->error =
+ node->errors[ESP_DECRYPT_ERROR_TUN_NO_PROTO];
+ }
+ }
+ else if (f->next_header == IP_PROTOCOL_IPV6)
+ {
+ const ip6_header_t *ip6;
+
+ ip6 = vlib_buffer_get_current (b[0]);
+
+ if (!ip46_address_is_equal_v6 (&itp->itp_tun.src,
+ &ip6->dst_address) ||
+ !ip46_address_is_equal_v6 (&itp->itp_tun.dst,
+ &ip6->src_address))
+ {
+ next[0] = ESP_DECRYPT_NEXT_DROP;
+ b[0]->error =
+ node->errors[ESP_DECRYPT_ERROR_TUN_NO_PROTO];
+ }
+ }
+ }