1b2441318SGreg Kroah-Hartman /* SPDX-License-Identifier: GPL-2.0 */
200959adeSDmitry Kozlov #ifndef __LINUX_GRE_H
300959adeSDmitry Kozlov #define __LINUX_GRE_H
400959adeSDmitry Kozlov
500959adeSDmitry Kozlov #include <linux/skbuff.h>
6c5441932SPravin B Shelar #include <net/ip_tunnels.h>
700959adeSDmitry Kozlov
89f57c67cSPravin B Shelar struct gre_base_hdr {
99f57c67cSPravin B Shelar __be16 flags;
109f57c67cSPravin B Shelar __be16 protocol;
11ab10dccbSGao Feng } __packed;
12ab10dccbSGao Feng
13ab10dccbSGao Feng struct gre_full_hdr {
14ab10dccbSGao Feng struct gre_base_hdr fixed_header;
15ab10dccbSGao Feng __be16 csum;
16ab10dccbSGao Feng __be16 reserved1;
17ab10dccbSGao Feng __be32 key;
18ab10dccbSGao Feng __be32 seq;
19ab10dccbSGao Feng } __packed;
209f57c67cSPravin B Shelar #define GRE_HEADER_SECTION 4
219f57c67cSPravin B Shelar
2200959adeSDmitry Kozlov #define GREPROTO_CISCO 0
2300959adeSDmitry Kozlov #define GREPROTO_PPTP 1
2400959adeSDmitry Kozlov #define GREPROTO_MAX 2
25bda7bb46SPravin B Shelar #define GRE_IP_PROTO_MAX 2
2600959adeSDmitry Kozlov
2700959adeSDmitry Kozlov struct gre_protocol {
2800959adeSDmitry Kozlov int (*handler)(struct sk_buff *skb);
2900959adeSDmitry Kozlov void (*err_handler)(struct sk_buff *skb, u32 info);
3000959adeSDmitry Kozlov };
3100959adeSDmitry Kozlov
3200959adeSDmitry Kozlov int gre_add_protocol(const struct gre_protocol *proto, u8 version);
3300959adeSDmitry Kozlov int gre_del_protocol(const struct gre_protocol *proto, u8 version);
3400959adeSDmitry Kozlov
35b2acd1dcSPravin B Shelar struct net_device *gretap_fb_dev_create(struct net *net, const char *name,
36b2acd1dcSPravin B Shelar u8 name_assign_type);
3795f5c64cSTom Herbert int gre_parse_header(struct sk_buff *skb, struct tnl_ptk_info *tpi,
38e582615aSEric Dumazet bool *csum_err, __be16 proto, int nhs);
3995f5c64cSTom Herbert
netif_is_gretap(const struct net_device * dev)400621e6fcSOz Shlomo static inline bool netif_is_gretap(const struct net_device *dev)
410621e6fcSOz Shlomo {
420621e6fcSOz Shlomo return dev->rtnl_link_ops &&
430621e6fcSOz Shlomo !strcmp(dev->rtnl_link_ops->kind, "gretap");
440621e6fcSOz Shlomo }
450621e6fcSOz Shlomo
netif_is_ip6gretap(const struct net_device * dev)460621e6fcSOz Shlomo static inline bool netif_is_ip6gretap(const struct net_device *dev)
470621e6fcSOz Shlomo {
480621e6fcSOz Shlomo return dev->rtnl_link_ops &&
490621e6fcSOz Shlomo !strcmp(dev->rtnl_link_ops->kind, "ip6gretap");
500621e6fcSOz Shlomo }
51d1b2a6c4SPetr Machata
gre_calc_hlen(__be16 o_flags)5295f5c64cSTom Herbert static inline int gre_calc_hlen(__be16 o_flags)
5395f5c64cSTom Herbert {
5495f5c64cSTom Herbert int addend = 4;
5595f5c64cSTom Herbert
5695f5c64cSTom Herbert if (o_flags & TUNNEL_CSUM)
5795f5c64cSTom Herbert addend += 4;
5895f5c64cSTom Herbert if (o_flags & TUNNEL_KEY)
5995f5c64cSTom Herbert addend += 4;
6095f5c64cSTom Herbert if (o_flags & TUNNEL_SEQ)
6195f5c64cSTom Herbert addend += 4;
6295f5c64cSTom Herbert return addend;
6395f5c64cSTom Herbert }
6495f5c64cSTom Herbert
gre_flags_to_tnl_flags(__be16 flags)6595f5c64cSTom Herbert static inline __be16 gre_flags_to_tnl_flags(__be16 flags)
6695f5c64cSTom Herbert {
6795f5c64cSTom Herbert __be16 tflags = 0;
6895f5c64cSTom Herbert
6995f5c64cSTom Herbert if (flags & GRE_CSUM)
7095f5c64cSTom Herbert tflags |= TUNNEL_CSUM;
7195f5c64cSTom Herbert if (flags & GRE_ROUTING)
7295f5c64cSTom Herbert tflags |= TUNNEL_ROUTING;
7395f5c64cSTom Herbert if (flags & GRE_KEY)
7495f5c64cSTom Herbert tflags |= TUNNEL_KEY;
7595f5c64cSTom Herbert if (flags & GRE_SEQ)
7695f5c64cSTom Herbert tflags |= TUNNEL_SEQ;
7795f5c64cSTom Herbert if (flags & GRE_STRICT)
7895f5c64cSTom Herbert tflags |= TUNNEL_STRICT;
7995f5c64cSTom Herbert if (flags & GRE_REC)
8095f5c64cSTom Herbert tflags |= TUNNEL_REC;
8195f5c64cSTom Herbert if (flags & GRE_VERSION)
8295f5c64cSTom Herbert tflags |= TUNNEL_VERSION;
8395f5c64cSTom Herbert
8495f5c64cSTom Herbert return tflags;
8595f5c64cSTom Herbert }
8695f5c64cSTom Herbert
gre_tnl_flags_to_gre_flags(__be16 tflags)8795f5c64cSTom Herbert static inline __be16 gre_tnl_flags_to_gre_flags(__be16 tflags)
8895f5c64cSTom Herbert {
8995f5c64cSTom Herbert __be16 flags = 0;
9095f5c64cSTom Herbert
9195f5c64cSTom Herbert if (tflags & TUNNEL_CSUM)
9295f5c64cSTom Herbert flags |= GRE_CSUM;
9395f5c64cSTom Herbert if (tflags & TUNNEL_ROUTING)
9495f5c64cSTom Herbert flags |= GRE_ROUTING;
9595f5c64cSTom Herbert if (tflags & TUNNEL_KEY)
9695f5c64cSTom Herbert flags |= GRE_KEY;
9795f5c64cSTom Herbert if (tflags & TUNNEL_SEQ)
9895f5c64cSTom Herbert flags |= GRE_SEQ;
9995f5c64cSTom Herbert if (tflags & TUNNEL_STRICT)
10095f5c64cSTom Herbert flags |= GRE_STRICT;
10195f5c64cSTom Herbert if (tflags & TUNNEL_REC)
10295f5c64cSTom Herbert flags |= GRE_REC;
10395f5c64cSTom Herbert if (tflags & TUNNEL_VERSION)
10495f5c64cSTom Herbert flags |= GRE_VERSION;
10595f5c64cSTom Herbert
10695f5c64cSTom Herbert return flags;
10795f5c64cSTom Herbert }
10895f5c64cSTom Herbert
gre_build_header(struct sk_buff * skb,int hdr_len,__be16 flags,__be16 proto,__be32 key,__be32 seq)109182a352dSTom Herbert static inline void gre_build_header(struct sk_buff *skb, int hdr_len,
110182a352dSTom Herbert __be16 flags, __be16 proto,
111182a352dSTom Herbert __be32 key, __be32 seq)
112182a352dSTom Herbert {
113182a352dSTom Herbert struct gre_base_hdr *greh;
114182a352dSTom Herbert
115182a352dSTom Herbert skb_push(skb, hdr_len);
116182a352dSTom Herbert
1173d7b3320SSimon Horman skb_set_inner_protocol(skb, proto);
118182a352dSTom Herbert skb_reset_transport_header(skb);
119182a352dSTom Herbert greh = (struct gre_base_hdr *)skb->data;
120182a352dSTom Herbert greh->flags = gre_tnl_flags_to_gre_flags(flags);
121182a352dSTom Herbert greh->protocol = proto;
122182a352dSTom Herbert
123182a352dSTom Herbert if (flags & (TUNNEL_KEY | TUNNEL_CSUM | TUNNEL_SEQ)) {
124182a352dSTom Herbert __be32 *ptr = (__be32 *)(((u8 *)greh) + hdr_len - 4);
125182a352dSTom Herbert
126182a352dSTom Herbert if (flags & TUNNEL_SEQ) {
127182a352dSTom Herbert *ptr = seq;
128182a352dSTom Herbert ptr--;
129182a352dSTom Herbert }
130182a352dSTom Herbert if (flags & TUNNEL_KEY) {
131182a352dSTom Herbert *ptr = key;
132182a352dSTom Herbert ptr--;
133182a352dSTom Herbert }
134182a352dSTom Herbert if (flags & TUNNEL_CSUM &&
135182a352dSTom Herbert !(skb_shinfo(skb)->gso_type &
136182a352dSTom Herbert (SKB_GSO_GRE | SKB_GSO_GRE_CSUM))) {
137182a352dSTom Herbert *ptr = 0;
138*efa1a65cSXin Long if (skb->ip_summed == CHECKSUM_PARTIAL) {
139*efa1a65cSXin Long *(__sum16 *)ptr = csum_fold(lco_csum(skb));
140*efa1a65cSXin Long } else {
141*efa1a65cSXin Long skb->ip_summed = CHECKSUM_PARTIAL;
142*efa1a65cSXin Long skb->csum_start = skb_transport_header(skb) - skb->head;
143*efa1a65cSXin Long skb->csum_offset = sizeof(*greh);
144*efa1a65cSXin Long }
145182a352dSTom Herbert }
146182a352dSTom Herbert }
147182a352dSTom Herbert }
148182a352dSTom Herbert
14900959adeSDmitry Kozlov #endif
150