1 /* 2 * GRE over IPv4 demultiplexer driver 3 * 4 * Authors: Dmitry Kozlov (xeb@mail.ru) 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 9 * 2 of the License, or (at your option) any later version. 10 * 11 */ 12 13 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 14 15 #include <linux/module.h> 16 #include <linux/if.h> 17 #include <linux/icmp.h> 18 #include <linux/kernel.h> 19 #include <linux/kmod.h> 20 #include <linux/skbuff.h> 21 #include <linux/in.h> 22 #include <linux/ip.h> 23 #include <linux/netdevice.h> 24 #include <linux/if_tunnel.h> 25 #include <linux/spinlock.h> 26 #include <net/protocol.h> 27 #include <net/gre.h> 28 #include <net/erspan.h> 29 30 #include <net/icmp.h> 31 #include <net/route.h> 32 #include <net/xfrm.h> 33 34 static const struct gre_protocol __rcu *gre_proto[GREPROTO_MAX] __read_mostly; 35 36 int gre_add_protocol(const struct gre_protocol *proto, u8 version) 37 { 38 if (version >= GREPROTO_MAX) 39 return -EINVAL; 40 41 return (cmpxchg((const struct gre_protocol **)&gre_proto[version], NULL, proto) == NULL) ? 42 0 : -EBUSY; 43 } 44 EXPORT_SYMBOL_GPL(gre_add_protocol); 45 46 int gre_del_protocol(const struct gre_protocol *proto, u8 version) 47 { 48 int ret; 49 50 if (version >= GREPROTO_MAX) 51 return -EINVAL; 52 53 ret = (cmpxchg((const struct gre_protocol **)&gre_proto[version], proto, NULL) == proto) ? 54 0 : -EBUSY; 55 56 if (ret) 57 return ret; 58 59 synchronize_rcu(); 60 return 0; 61 } 62 EXPORT_SYMBOL_GPL(gre_del_protocol); 63 64 /* Fills in tpi and returns header length to be pulled. */ 65 int gre_parse_header(struct sk_buff *skb, struct tnl_ptk_info *tpi, 66 bool *csum_err, __be16 proto, int nhs) 67 { 68 const struct gre_base_hdr *greh; 69 __be32 *options; 70 int hdr_len; 71 72 if (unlikely(!pskb_may_pull(skb, nhs + sizeof(struct gre_base_hdr)))) 73 return -EINVAL; 74 75 greh = (struct gre_base_hdr *)(skb->data + nhs); 76 if (unlikely(greh->flags & (GRE_VERSION | GRE_ROUTING))) 77 return -EINVAL; 78 79 tpi->flags = gre_flags_to_tnl_flags(greh->flags); 80 hdr_len = gre_calc_hlen(tpi->flags); 81 82 if (!pskb_may_pull(skb, nhs + hdr_len)) 83 return -EINVAL; 84 85 greh = (struct gre_base_hdr *)(skb->data + nhs); 86 tpi->proto = greh->protocol; 87 88 options = (__be32 *)(greh + 1); 89 if (greh->flags & GRE_CSUM) { 90 if (!skb_checksum_simple_validate(skb)) { 91 skb_checksum_try_convert(skb, IPPROTO_GRE, 0, 92 null_compute_pseudo); 93 } else if (csum_err) { 94 *csum_err = true; 95 return -EINVAL; 96 } 97 98 options++; 99 } 100 101 if (greh->flags & GRE_KEY) { 102 tpi->key = *options; 103 options++; 104 } else { 105 tpi->key = 0; 106 } 107 if (unlikely(greh->flags & GRE_SEQ)) { 108 tpi->seq = *options; 109 options++; 110 } else { 111 tpi->seq = 0; 112 } 113 /* WCCP version 1 and 2 protocol decoding. 114 * - Change protocol to IPv4/IPv6 115 * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header 116 */ 117 if (greh->flags == 0 && tpi->proto == htons(ETH_P_WCCP)) { 118 tpi->proto = proto; 119 if ((*(u8 *)options & 0xF0) != 0x40) 120 hdr_len += 4; 121 } 122 tpi->hdr_len = hdr_len; 123 124 /* ERSPAN ver 1 and 2 protocol sets GRE key field 125 * to 0 and sets the configured key in the 126 * inner erspan header field 127 */ 128 if (greh->protocol == htons(ETH_P_ERSPAN) || 129 greh->protocol == htons(ETH_P_ERSPAN2)) { 130 struct erspan_base_hdr *ershdr; 131 132 if (!pskb_may_pull(skb, nhs + hdr_len + sizeof(*ershdr))) 133 return -EINVAL; 134 135 ershdr = (struct erspan_base_hdr *)options; 136 tpi->key = cpu_to_be32(get_session_id(ershdr)); 137 } 138 139 return hdr_len; 140 } 141 EXPORT_SYMBOL(gre_parse_header); 142 143 static int gre_rcv(struct sk_buff *skb) 144 { 145 const struct gre_protocol *proto; 146 u8 ver; 147 int ret; 148 149 if (!pskb_may_pull(skb, 12)) 150 goto drop; 151 152 ver = skb->data[1]&0x7f; 153 if (ver >= GREPROTO_MAX) 154 goto drop; 155 156 rcu_read_lock(); 157 proto = rcu_dereference(gre_proto[ver]); 158 if (!proto || !proto->handler) 159 goto drop_unlock; 160 ret = proto->handler(skb); 161 rcu_read_unlock(); 162 return ret; 163 164 drop_unlock: 165 rcu_read_unlock(); 166 drop: 167 kfree_skb(skb); 168 return NET_RX_DROP; 169 } 170 171 static int gre_err(struct sk_buff *skb, u32 info) 172 { 173 const struct gre_protocol *proto; 174 const struct iphdr *iph = (const struct iphdr *)skb->data; 175 u8 ver = skb->data[(iph->ihl<<2) + 1]&0x7f; 176 int err = 0; 177 178 if (ver >= GREPROTO_MAX) 179 return -EINVAL; 180 181 rcu_read_lock(); 182 proto = rcu_dereference(gre_proto[ver]); 183 if (proto && proto->err_handler) 184 proto->err_handler(skb, info); 185 else 186 err = -EPROTONOSUPPORT; 187 rcu_read_unlock(); 188 189 return err; 190 } 191 192 static const struct net_protocol net_gre_protocol = { 193 .handler = gre_rcv, 194 .err_handler = gre_err, 195 .netns_ok = 1, 196 }; 197 198 static int __init gre_init(void) 199 { 200 pr_info("GRE over IPv4 demultiplexor driver\n"); 201 202 if (inet_add_protocol(&net_gre_protocol, IPPROTO_GRE) < 0) { 203 pr_err("can't add protocol\n"); 204 return -EAGAIN; 205 } 206 return 0; 207 } 208 209 static void __exit gre_exit(void) 210 { 211 inet_del_protocol(&net_gre_protocol, IPPROTO_GRE); 212 } 213 214 module_init(gre_init); 215 module_exit(gre_exit); 216 217 MODULE_DESCRIPTION("GRE over IPv4 demultiplexer driver"); 218 MODULE_AUTHOR("D. Kozlov (xeb@mail.ru)"); 219 MODULE_LICENSE("GPL"); 220