-static int parse_header(struct iphdr *iph, __be16 *flags, __be64 *tun_id,
- u32 *tunnel_type)
-{
- /* IP and ICMP protocol handlers check that the IHL is valid. */
- struct gre_base_hdr *greh = (struct gre_base_hdr *)((u8 *)iph + (iph->ihl << 2));
- __be32 *options = (__be32 *)(greh + 1);
- int hdr_len;
-
- *flags = greh->flags;
-
- if (unlikely(greh->flags & (GRE_VERSION | GRE_ROUTING)))
- return -EINVAL;
-
- if (unlikely(greh->protocol != htons(ETH_P_TEB)))
- return -EINVAL;
-
- hdr_len = GRE_HEADER_SECTION;
-
- if (greh->flags & GRE_CSUM) {
- hdr_len += GRE_HEADER_SECTION;
- options++;
- }
-
- if (greh->flags & GRE_KEY) {
- __be32 seq;
- __be32 gre_key;
-
- gre_key = *options;
- hdr_len += GRE_HEADER_SECTION;
- options++;
-
- if (greh->flags & GRE_SEQ) {
- seq = *options;
- *tunnel_type = TNL_T_PROTO_GRE64;
- } else {
- seq = 0;
- *tunnel_type = TNL_T_PROTO_GRE;
- }
- *tun_id = key_to_tunnel_id(gre_key, seq);
- } else {
- *tun_id = 0;
- /* Ignore GRE seq if there is no key present. */
- *tunnel_type = TNL_T_PROTO_GRE;
- }
-
- if (greh->flags & GRE_SEQ)
- hdr_len += GRE_HEADER_SECTION;
-
- return hdr_len;
-}
-