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