18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci#ifndef __LINUX_GRE_H
38c2ecf20Sopenharmony_ci#define __LINUX_GRE_H
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci#include <linux/skbuff.h>
68c2ecf20Sopenharmony_ci#include <net/ip_tunnels.h>
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_cistruct gre_base_hdr {
98c2ecf20Sopenharmony_ci	__be16 flags;
108c2ecf20Sopenharmony_ci	__be16 protocol;
118c2ecf20Sopenharmony_ci} __packed;
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_cistruct gre_full_hdr {
148c2ecf20Sopenharmony_ci	struct gre_base_hdr fixed_header;
158c2ecf20Sopenharmony_ci	__be16 csum;
168c2ecf20Sopenharmony_ci	__be16 reserved1;
178c2ecf20Sopenharmony_ci	__be32 key;
188c2ecf20Sopenharmony_ci	__be32 seq;
198c2ecf20Sopenharmony_ci} __packed;
208c2ecf20Sopenharmony_ci#define GRE_HEADER_SECTION 4
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#define GREPROTO_CISCO		0
238c2ecf20Sopenharmony_ci#define GREPROTO_PPTP		1
248c2ecf20Sopenharmony_ci#define GREPROTO_MAX		2
258c2ecf20Sopenharmony_ci#define GRE_IP_PROTO_MAX	2
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_cistruct gre_protocol {
288c2ecf20Sopenharmony_ci	int  (*handler)(struct sk_buff *skb);
298c2ecf20Sopenharmony_ci	void (*err_handler)(struct sk_buff *skb, u32 info);
308c2ecf20Sopenharmony_ci};
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ciint gre_add_protocol(const struct gre_protocol *proto, u8 version);
338c2ecf20Sopenharmony_ciint gre_del_protocol(const struct gre_protocol *proto, u8 version);
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cistruct net_device *gretap_fb_dev_create(struct net *net, const char *name,
368c2ecf20Sopenharmony_ci				       u8 name_assign_type);
378c2ecf20Sopenharmony_ciint gre_parse_header(struct sk_buff *skb, struct tnl_ptk_info *tpi,
388c2ecf20Sopenharmony_ci		     bool *csum_err, __be16 proto, int nhs);
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_cistatic inline bool netif_is_gretap(const struct net_device *dev)
418c2ecf20Sopenharmony_ci{
428c2ecf20Sopenharmony_ci	return dev->rtnl_link_ops &&
438c2ecf20Sopenharmony_ci	       !strcmp(dev->rtnl_link_ops->kind, "gretap");
448c2ecf20Sopenharmony_ci}
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_cistatic inline bool netif_is_ip6gretap(const struct net_device *dev)
478c2ecf20Sopenharmony_ci{
488c2ecf20Sopenharmony_ci	return dev->rtnl_link_ops &&
498c2ecf20Sopenharmony_ci	       !strcmp(dev->rtnl_link_ops->kind, "ip6gretap");
508c2ecf20Sopenharmony_ci}
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_cistatic inline int gre_calc_hlen(__be16 o_flags)
538c2ecf20Sopenharmony_ci{
548c2ecf20Sopenharmony_ci	int addend = 4;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	if (o_flags & TUNNEL_CSUM)
578c2ecf20Sopenharmony_ci		addend += 4;
588c2ecf20Sopenharmony_ci	if (o_flags & TUNNEL_KEY)
598c2ecf20Sopenharmony_ci		addend += 4;
608c2ecf20Sopenharmony_ci	if (o_flags & TUNNEL_SEQ)
618c2ecf20Sopenharmony_ci		addend += 4;
628c2ecf20Sopenharmony_ci	return addend;
638c2ecf20Sopenharmony_ci}
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_cistatic inline __be16 gre_flags_to_tnl_flags(__be16 flags)
668c2ecf20Sopenharmony_ci{
678c2ecf20Sopenharmony_ci	__be16 tflags = 0;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	if (flags & GRE_CSUM)
708c2ecf20Sopenharmony_ci		tflags |= TUNNEL_CSUM;
718c2ecf20Sopenharmony_ci	if (flags & GRE_ROUTING)
728c2ecf20Sopenharmony_ci		tflags |= TUNNEL_ROUTING;
738c2ecf20Sopenharmony_ci	if (flags & GRE_KEY)
748c2ecf20Sopenharmony_ci		tflags |= TUNNEL_KEY;
758c2ecf20Sopenharmony_ci	if (flags & GRE_SEQ)
768c2ecf20Sopenharmony_ci		tflags |= TUNNEL_SEQ;
778c2ecf20Sopenharmony_ci	if (flags & GRE_STRICT)
788c2ecf20Sopenharmony_ci		tflags |= TUNNEL_STRICT;
798c2ecf20Sopenharmony_ci	if (flags & GRE_REC)
808c2ecf20Sopenharmony_ci		tflags |= TUNNEL_REC;
818c2ecf20Sopenharmony_ci	if (flags & GRE_VERSION)
828c2ecf20Sopenharmony_ci		tflags |= TUNNEL_VERSION;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	return tflags;
858c2ecf20Sopenharmony_ci}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_cistatic inline __be16 gre_tnl_flags_to_gre_flags(__be16 tflags)
888c2ecf20Sopenharmony_ci{
898c2ecf20Sopenharmony_ci	__be16 flags = 0;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	if (tflags & TUNNEL_CSUM)
928c2ecf20Sopenharmony_ci		flags |= GRE_CSUM;
938c2ecf20Sopenharmony_ci	if (tflags & TUNNEL_ROUTING)
948c2ecf20Sopenharmony_ci		flags |= GRE_ROUTING;
958c2ecf20Sopenharmony_ci	if (tflags & TUNNEL_KEY)
968c2ecf20Sopenharmony_ci		flags |= GRE_KEY;
978c2ecf20Sopenharmony_ci	if (tflags & TUNNEL_SEQ)
988c2ecf20Sopenharmony_ci		flags |= GRE_SEQ;
998c2ecf20Sopenharmony_ci	if (tflags & TUNNEL_STRICT)
1008c2ecf20Sopenharmony_ci		flags |= GRE_STRICT;
1018c2ecf20Sopenharmony_ci	if (tflags & TUNNEL_REC)
1028c2ecf20Sopenharmony_ci		flags |= GRE_REC;
1038c2ecf20Sopenharmony_ci	if (tflags & TUNNEL_VERSION)
1048c2ecf20Sopenharmony_ci		flags |= GRE_VERSION;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	return flags;
1078c2ecf20Sopenharmony_ci}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_cistatic inline __sum16 gre_checksum(struct sk_buff *skb)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	__wsum csum;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	if (skb->ip_summed == CHECKSUM_PARTIAL)
1148c2ecf20Sopenharmony_ci		csum = lco_csum(skb);
1158c2ecf20Sopenharmony_ci	else
1168c2ecf20Sopenharmony_ci		csum = skb_checksum(skb, 0, skb->len, 0);
1178c2ecf20Sopenharmony_ci	return csum_fold(csum);
1188c2ecf20Sopenharmony_ci}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_cistatic inline void gre_build_header(struct sk_buff *skb, int hdr_len,
1218c2ecf20Sopenharmony_ci				    __be16 flags, __be16 proto,
1228c2ecf20Sopenharmony_ci				    __be32 key, __be32 seq)
1238c2ecf20Sopenharmony_ci{
1248c2ecf20Sopenharmony_ci	struct gre_base_hdr *greh;
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	skb_push(skb, hdr_len);
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	skb_set_inner_protocol(skb, proto);
1298c2ecf20Sopenharmony_ci	skb_reset_transport_header(skb);
1308c2ecf20Sopenharmony_ci	greh = (struct gre_base_hdr *)skb->data;
1318c2ecf20Sopenharmony_ci	greh->flags = gre_tnl_flags_to_gre_flags(flags);
1328c2ecf20Sopenharmony_ci	greh->protocol = proto;
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	if (flags & (TUNNEL_KEY | TUNNEL_CSUM | TUNNEL_SEQ)) {
1358c2ecf20Sopenharmony_ci		__be32 *ptr = (__be32 *)(((u8 *)greh) + hdr_len - 4);
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci		if (flags & TUNNEL_SEQ) {
1388c2ecf20Sopenharmony_ci			*ptr = seq;
1398c2ecf20Sopenharmony_ci			ptr--;
1408c2ecf20Sopenharmony_ci		}
1418c2ecf20Sopenharmony_ci		if (flags & TUNNEL_KEY) {
1428c2ecf20Sopenharmony_ci			*ptr = key;
1438c2ecf20Sopenharmony_ci			ptr--;
1448c2ecf20Sopenharmony_ci		}
1458c2ecf20Sopenharmony_ci		if (flags & TUNNEL_CSUM &&
1468c2ecf20Sopenharmony_ci		    !(skb_shinfo(skb)->gso_type &
1478c2ecf20Sopenharmony_ci		      (SKB_GSO_GRE | SKB_GSO_GRE_CSUM))) {
1488c2ecf20Sopenharmony_ci			*ptr = 0;
1498c2ecf20Sopenharmony_ci			*(__sum16 *)ptr = gre_checksum(skb);
1508c2ecf20Sopenharmony_ci		}
1518c2ecf20Sopenharmony_ci	}
1528c2ecf20Sopenharmony_ci}
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci#endif
155