100959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov/* 200959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov * GRE over IPv4 demultiplexer driver 300959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov * 400959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov * Authors: Dmitry Kozlov (xeb@mail.ru) 500959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov * 600959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov * This program is free software; you can redistribute it and/or 700959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov * modify it under the terms of the GNU General Public License 800959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov * as published by the Free Software Foundation; either version 900959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov * 2 of the License, or (at your option) any later version. 1000959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov * 1100959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov */ 1200959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov 13afd465030acb4098abcb6b965a5aebc7ea2209e0Joe Perches#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 14afd465030acb4098abcb6b965a5aebc7ea2209e0Joe Perches 1500959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov#include <linux/module.h> 16bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar#include <linux/if.h> 17bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar#include <linux/icmp.h> 1800959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov#include <linux/kernel.h> 1900959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov#include <linux/kmod.h> 2000959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov#include <linux/skbuff.h> 2100959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov#include <linux/in.h> 22559fafb94ad9e4cd8774f39241917c57396f9fc5xeb@mail.ru#include <linux/ip.h> 2300959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov#include <linux/netdevice.h> 2468c331631143f5f039baac99a650e0b9e1ea02b6Pravin B Shelar#include <linux/if_tunnel.h> 2500959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov#include <linux/spinlock.h> 2600959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov#include <net/protocol.h> 2700959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov#include <net/gre.h> 2800959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov 29bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar#include <net/icmp.h> 30bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar#include <net/route.h> 31bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar#include <net/xfrm.h> 3200959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov 336f0bcf152582e7403155627a38e07bf3ef7f3cf5Eric Dumazetstatic const struct gre_protocol __rcu *gre_proto[GREPROTO_MAX] __read_mostly; 34bda7bb46343647f68591366731295a0f3eea59edPravin B Shelarstatic struct gre_cisco_protocol __rcu *gre_cisco_proto_list[GRE_IP_PROTO_MAX]; 3500959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov 3600959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlovint gre_add_protocol(const struct gre_protocol *proto, u8 version) 3700959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov{ 3800959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov if (version >= GREPROTO_MAX) 3920fd4d1f04da07d09192ad8ad366a70d5125bfafPravin B Shelar return -EINVAL; 4000959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov 4120fd4d1f04da07d09192ad8ad366a70d5125bfafPravin B Shelar return (cmpxchg((const struct gre_protocol **)&gre_proto[version], NULL, proto) == NULL) ? 4220fd4d1f04da07d09192ad8ad366a70d5125bfafPravin B Shelar 0 : -EBUSY; 4300959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov} 4400959ade36acadc00e757f87060bf6e4501d545fDmitry KozlovEXPORT_SYMBOL_GPL(gre_add_protocol); 4500959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov 4600959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlovint gre_del_protocol(const struct gre_protocol *proto, u8 version) 4700959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov{ 4820fd4d1f04da07d09192ad8ad366a70d5125bfafPravin B Shelar int ret; 4920fd4d1f04da07d09192ad8ad366a70d5125bfafPravin B Shelar 5000959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov if (version >= GREPROTO_MAX) 5120fd4d1f04da07d09192ad8ad366a70d5125bfafPravin B Shelar return -EINVAL; 5220fd4d1f04da07d09192ad8ad366a70d5125bfafPravin B Shelar 5320fd4d1f04da07d09192ad8ad366a70d5125bfafPravin B Shelar ret = (cmpxchg((const struct gre_protocol **)&gre_proto[version], proto, NULL) == proto) ? 5420fd4d1f04da07d09192ad8ad366a70d5125bfafPravin B Shelar 0 : -EBUSY; 5520fd4d1f04da07d09192ad8ad366a70d5125bfafPravin B Shelar 5620fd4d1f04da07d09192ad8ad366a70d5125bfafPravin B Shelar if (ret) 5720fd4d1f04da07d09192ad8ad366a70d5125bfafPravin B Shelar return ret; 5820fd4d1f04da07d09192ad8ad366a70d5125bfafPravin B Shelar 5900959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov synchronize_rcu(); 6000959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov return 0; 6100959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov} 6200959ade36acadc00e757f87060bf6e4501d545fDmitry KozlovEXPORT_SYMBOL_GPL(gre_del_protocol); 6300959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov 64752f36da68e9136df8918461d651723a43627e04Pravin B Shelarvoid gre_build_header(struct sk_buff *skb, const struct tnl_ptk_info *tpi, 65752f36da68e9136df8918461d651723a43627e04Pravin B Shelar int hdr_len) 66752f36da68e9136df8918461d651723a43627e04Pravin B Shelar{ 67752f36da68e9136df8918461d651723a43627e04Pravin B Shelar struct gre_base_hdr *greh; 68752f36da68e9136df8918461d651723a43627e04Pravin B Shelar 69752f36da68e9136df8918461d651723a43627e04Pravin B Shelar skb_push(skb, hdr_len); 70752f36da68e9136df8918461d651723a43627e04Pravin B Shelar 71d0a7ebbc119738439ff00f7fadbd343ae20ea5e8Amritha Nambiar skb_reset_transport_header(skb); 72752f36da68e9136df8918461d651723a43627e04Pravin B Shelar greh = (struct gre_base_hdr *)skb->data; 73752f36da68e9136df8918461d651723a43627e04Pravin B Shelar greh->flags = tnl_flags_to_gre_flags(tpi->flags); 74752f36da68e9136df8918461d651723a43627e04Pravin B Shelar greh->protocol = tpi->proto; 75752f36da68e9136df8918461d651723a43627e04Pravin B Shelar 76752f36da68e9136df8918461d651723a43627e04Pravin B Shelar if (tpi->flags&(TUNNEL_KEY|TUNNEL_CSUM|TUNNEL_SEQ)) { 77752f36da68e9136df8918461d651723a43627e04Pravin B Shelar __be32 *ptr = (__be32 *)(((u8 *)greh) + hdr_len - 4); 78752f36da68e9136df8918461d651723a43627e04Pravin B Shelar 79752f36da68e9136df8918461d651723a43627e04Pravin B Shelar if (tpi->flags&TUNNEL_SEQ) { 80752f36da68e9136df8918461d651723a43627e04Pravin B Shelar *ptr = tpi->seq; 81752f36da68e9136df8918461d651723a43627e04Pravin B Shelar ptr--; 82752f36da68e9136df8918461d651723a43627e04Pravin B Shelar } 83752f36da68e9136df8918461d651723a43627e04Pravin B Shelar if (tpi->flags&TUNNEL_KEY) { 84752f36da68e9136df8918461d651723a43627e04Pravin B Shelar *ptr = tpi->key; 85752f36da68e9136df8918461d651723a43627e04Pravin B Shelar ptr--; 86752f36da68e9136df8918461d651723a43627e04Pravin B Shelar } 87752f36da68e9136df8918461d651723a43627e04Pravin B Shelar if (tpi->flags&TUNNEL_CSUM && 884749c09c37030ccdc44aecebe0f71b02a377fc14Tom Herbert !(skb_shinfo(skb)->gso_type & 894749c09c37030ccdc44aecebe0f71b02a377fc14Tom Herbert (SKB_GSO_GRE|SKB_GSO_GRE_CSUM))) { 90752f36da68e9136df8918461d651723a43627e04Pravin B Shelar *ptr = 0; 91752f36da68e9136df8918461d651723a43627e04Pravin B Shelar *(__sum16 *)ptr = csum_fold(skb_checksum(skb, 0, 92752f36da68e9136df8918461d651723a43627e04Pravin B Shelar skb->len, 0)); 93752f36da68e9136df8918461d651723a43627e04Pravin B Shelar } 94752f36da68e9136df8918461d651723a43627e04Pravin B Shelar } 95752f36da68e9136df8918461d651723a43627e04Pravin B Shelar} 96752f36da68e9136df8918461d651723a43627e04Pravin B ShelarEXPORT_SYMBOL_GPL(gre_build_header); 97752f36da68e9136df8918461d651723a43627e04Pravin B Shelar 98bda7bb46343647f68591366731295a0f3eea59edPravin B Shelarstatic int parse_gre_header(struct sk_buff *skb, struct tnl_ptk_info *tpi, 99bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar bool *csum_err) 100bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar{ 101bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar const struct gre_base_hdr *greh; 102bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar __be32 *options; 103bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar int hdr_len; 104bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar 105bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar if (unlikely(!pskb_may_pull(skb, sizeof(struct gre_base_hdr)))) 106bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar return -EINVAL; 107bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar 1081e701f16982a9d15488a5aa8c7f5c41444b1de67Tom Herbert greh = (struct gre_base_hdr *)skb_transport_header(skb); 109bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar if (unlikely(greh->flags & (GRE_VERSION | GRE_ROUTING))) 110bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar return -EINVAL; 111bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar 112bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar tpi->flags = gre_flags_to_tnl_flags(greh->flags); 113bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar hdr_len = ip_gre_calc_hlen(tpi->flags); 114bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar 115bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar if (!pskb_may_pull(skb, hdr_len)) 116bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar return -EINVAL; 117bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar 1181e701f16982a9d15488a5aa8c7f5c41444b1de67Tom Herbert greh = (struct gre_base_hdr *)skb_transport_header(skb); 119bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar tpi->proto = greh->protocol; 120bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar 121bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar options = (__be32 *)(greh + 1); 122bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar if (greh->flags & GRE_CSUM) { 123b1036c6a470ccf5f18490a7ce4c99422d3bf77c4Tom Herbert if (skb_checksum_simple_validate(skb)) { 124bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar *csum_err = true; 125bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar return -EINVAL; 126bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar } 127884d338c041c2aa4536ade8620efa585e7c57f3cTom Herbert 128884d338c041c2aa4536ade8620efa585e7c57f3cTom Herbert skb_checksum_try_convert(skb, IPPROTO_GRE, 0, 129884d338c041c2aa4536ade8620efa585e7c57f3cTom Herbert null_compute_pseudo); 130884d338c041c2aa4536ade8620efa585e7c57f3cTom Herbert 131bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar options++; 132bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar } 133bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar 134bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar if (greh->flags & GRE_KEY) { 135bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar tpi->key = *options; 136bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar options++; 137bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar } else 138bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar tpi->key = 0; 139bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar 140bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar if (unlikely(greh->flags & GRE_SEQ)) { 141bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar tpi->seq = *options; 142bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar options++; 143bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar } else 144bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar tpi->seq = 0; 145bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar 146bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar /* WCCP version 1 and 2 protocol decoding. 147bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar * - Change protocol to IP 148bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header 149bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar */ 150bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar if (greh->flags == 0 && tpi->proto == htons(ETH_P_WCCP)) { 151bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar tpi->proto = htons(ETH_P_IP); 152bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar if ((*(u8 *)options & 0xF0) != 0x40) { 153bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar hdr_len += 4; 154bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar if (!pskb_may_pull(skb, hdr_len)) 155bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar return -EINVAL; 156bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar } 157bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar } 1583d7b46cd20e300bd6989fb1f43d46f1b9645816ePravin B Shelar 1593d7b46cd20e300bd6989fb1f43d46f1b9645816ePravin B Shelar return iptunnel_pull_header(skb, hdr_len, tpi->proto); 160bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar} 161bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar 162bda7bb46343647f68591366731295a0f3eea59edPravin B Shelarstatic int gre_cisco_rcv(struct sk_buff *skb) 163bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar{ 164bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar struct tnl_ptk_info tpi; 165bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar int i; 166bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar bool csum_err = false; 167bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar 168fbd02dd405d0724a0f25897ed4a6813297c9b96fPravin B Shelar#ifdef CONFIG_NET_IPGRE_BROADCAST 169fbd02dd405d0724a0f25897ed4a6813297c9b96fPravin B Shelar if (ipv4_is_multicast(ip_hdr(skb)->daddr)) { 170fbd02dd405d0724a0f25897ed4a6813297c9b96fPravin B Shelar /* Looped back packet, drop it! */ 171fbd02dd405d0724a0f25897ed4a6813297c9b96fPravin B Shelar if (rt_is_output_route(skb_rtable(skb))) 172fbd02dd405d0724a0f25897ed4a6813297c9b96fPravin B Shelar goto drop; 173fbd02dd405d0724a0f25897ed4a6813297c9b96fPravin B Shelar } 174fbd02dd405d0724a0f25897ed4a6813297c9b96fPravin B Shelar#endif 175fbd02dd405d0724a0f25897ed4a6813297c9b96fPravin B Shelar 176bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar if (parse_gre_header(skb, &tpi, &csum_err) < 0) 177bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar goto drop; 178bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar 179bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar rcu_read_lock(); 180bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar for (i = 0; i < GRE_IP_PROTO_MAX; i++) { 181bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar struct gre_cisco_protocol *proto; 182bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar int ret; 183bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar 184bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar proto = rcu_dereference(gre_cisco_proto_list[i]); 185bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar if (!proto) 186bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar continue; 187bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar ret = proto->handler(skb, &tpi); 188bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar if (ret == PACKET_RCVD) { 189bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar rcu_read_unlock(); 190bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar return 0; 191bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar } 192bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar } 193bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar rcu_read_unlock(); 194bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar 195bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); 196bda7bb46343647f68591366731295a0f3eea59edPravin B Shelardrop: 197bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar kfree_skb(skb); 198bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar return 0; 199bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar} 200bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar 201bda7bb46343647f68591366731295a0f3eea59edPravin B Shelarstatic void gre_cisco_err(struct sk_buff *skb, u32 info) 202bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar{ 203bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar /* All the routers (except for Linux) return only 204bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar * 8 bytes of packet payload. It means, that precise relaying of 205bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar * ICMP in the real Internet is absolutely infeasible. 206bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar * 207bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar * Moreover, Cisco "wise men" put GRE key to the third word 208bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar * in GRE header. It makes impossible maintaining even soft 209bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar * state for keyed 210bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar * GRE tunnels with enabled checksum. Tell them "thank you". 211bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar * 212bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar * Well, I wonder, rfc1812 was written by Cisco employee, 213bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar * what the hell these idiots break standards established 214bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar * by themselves??? 215bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar */ 216bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar 217bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar const int type = icmp_hdr(skb)->type; 218bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar const int code = icmp_hdr(skb)->code; 219bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar struct tnl_ptk_info tpi; 220bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar bool csum_err = false; 221bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar int i; 222bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar 223bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar if (parse_gre_header(skb, &tpi, &csum_err)) { 224bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar if (!csum_err) /* ignore csum errors. */ 225bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar return; 226bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar } 227bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar 228bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) { 229bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar ipv4_update_pmtu(skb, dev_net(skb->dev), info, 230bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar skb->dev->ifindex, 0, IPPROTO_GRE, 0); 231bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar return; 232bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar } 233bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar if (type == ICMP_REDIRECT) { 234bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar ipv4_redirect(skb, dev_net(skb->dev), skb->dev->ifindex, 0, 235bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar IPPROTO_GRE, 0); 236bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar return; 237bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar } 238bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar 239bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar rcu_read_lock(); 240bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar for (i = 0; i < GRE_IP_PROTO_MAX; i++) { 241bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar struct gre_cisco_protocol *proto; 242bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar 243bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar proto = rcu_dereference(gre_cisco_proto_list[i]); 244bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar if (!proto) 245bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar continue; 246bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar 247bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar if (proto->err_handler(skb, info, &tpi) == PACKET_RCVD) 248bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar goto out; 249bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar 250bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar } 251bda7bb46343647f68591366731295a0f3eea59edPravin B Shelarout: 252bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar rcu_read_unlock(); 253bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar} 254bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar 25500959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlovstatic int gre_rcv(struct sk_buff *skb) 25600959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov{ 25700959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov const struct gre_protocol *proto; 25800959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov u8 ver; 25900959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov int ret; 26000959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov 26100959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov if (!pskb_may_pull(skb, 12)) 26200959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov goto drop; 26300959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov 26400959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov ver = skb->data[1]&0x7f; 26500959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov if (ver >= GREPROTO_MAX) 26600959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov goto drop; 26700959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov 26800959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov rcu_read_lock(); 26900959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov proto = rcu_dereference(gre_proto[ver]); 27000959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov if (!proto || !proto->handler) 27100959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov goto drop_unlock; 27200959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov ret = proto->handler(skb); 27300959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov rcu_read_unlock(); 27400959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov return ret; 27500959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov 27600959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlovdrop_unlock: 27700959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov rcu_read_unlock(); 27800959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlovdrop: 27900959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov kfree_skb(skb); 28000959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov return NET_RX_DROP; 28100959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov} 28200959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov 28300959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlovstatic void gre_err(struct sk_buff *skb, u32 info) 28400959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov{ 28500959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov const struct gre_protocol *proto; 286559fafb94ad9e4cd8774f39241917c57396f9fc5xeb@mail.ru const struct iphdr *iph = (const struct iphdr *)skb->data; 287559fafb94ad9e4cd8774f39241917c57396f9fc5xeb@mail.ru u8 ver = skb->data[(iph->ihl<<2) + 1]&0x7f; 28800959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov 28900959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov if (ver >= GREPROTO_MAX) 290559fafb94ad9e4cd8774f39241917c57396f9fc5xeb@mail.ru return; 29100959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov 29200959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov rcu_read_lock(); 29300959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov proto = rcu_dereference(gre_proto[ver]); 294559fafb94ad9e4cd8774f39241917c57396f9fc5xeb@mail.ru if (proto && proto->err_handler) 295559fafb94ad9e4cd8774f39241917c57396f9fc5xeb@mail.ru proto->err_handler(skb, info); 29600959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov rcu_read_unlock(); 29700959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov} 29800959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov 29900959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlovstatic const struct net_protocol net_gre_protocol = { 30000959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov .handler = gre_rcv, 30100959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov .err_handler = gre_err, 30200959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov .netns_ok = 1, 30300959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov}; 30400959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov 305bda7bb46343647f68591366731295a0f3eea59edPravin B Shelarstatic const struct gre_protocol ipgre_protocol = { 306bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar .handler = gre_cisco_rcv, 307bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar .err_handler = gre_cisco_err, 308bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar}; 309bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar 310bda7bb46343647f68591366731295a0f3eea59edPravin B Shelarint gre_cisco_register(struct gre_cisco_protocol *newp) 311bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar{ 312bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar struct gre_cisco_protocol **proto = (struct gre_cisco_protocol **) 313bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar &gre_cisco_proto_list[newp->priority]; 314bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar 315bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar return (cmpxchg(proto, NULL, newp) == NULL) ? 0 : -EBUSY; 316bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar} 317bda7bb46343647f68591366731295a0f3eea59edPravin B ShelarEXPORT_SYMBOL_GPL(gre_cisco_register); 318bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar 319bda7bb46343647f68591366731295a0f3eea59edPravin B Shelarint gre_cisco_unregister(struct gre_cisco_protocol *del_proto) 320bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar{ 321bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar struct gre_cisco_protocol **proto = (struct gre_cisco_protocol **) 322bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar &gre_cisco_proto_list[del_proto->priority]; 323bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar int ret; 324bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar 325bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar ret = (cmpxchg(proto, del_proto, NULL) == del_proto) ? 0 : -EINVAL; 326bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar 327bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar if (ret) 328bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar return ret; 329bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar 330bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar synchronize_net(); 331bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar return 0; 332bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar} 333bda7bb46343647f68591366731295a0f3eea59edPravin B ShelarEXPORT_SYMBOL_GPL(gre_cisco_unregister); 334bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar 33500959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlovstatic int __init gre_init(void) 33600959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov{ 337afd465030acb4098abcb6b965a5aebc7ea2209e0Joe Perches pr_info("GRE over IPv4 demultiplexor driver\n"); 33800959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov 33900959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov if (inet_add_protocol(&net_gre_protocol, IPPROTO_GRE) < 0) { 340afd465030acb4098abcb6b965a5aebc7ea2209e0Joe Perches pr_err("can't add protocol\n"); 341bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar goto err; 342bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar } 343bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar 344bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar if (gre_add_protocol(&ipgre_protocol, GREPROTO_CISCO) < 0) { 345bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar pr_info("%s: can't add ipgre handler\n", __func__); 346bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar goto err_gre; 34700959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov } 34800959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov 34900959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov return 0; 350bda7bb46343647f68591366731295a0f3eea59edPravin B Shelarerr_gre: 351bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar inet_del_protocol(&net_gre_protocol, IPPROTO_GRE); 352bda7bb46343647f68591366731295a0f3eea59edPravin B Shelarerr: 353bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar return -EAGAIN; 35400959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov} 35500959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov 35600959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlovstatic void __exit gre_exit(void) 35700959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov{ 358bda7bb46343647f68591366731295a0f3eea59edPravin B Shelar gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO); 35900959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov inet_del_protocol(&net_gre_protocol, IPPROTO_GRE); 36000959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov} 36100959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov 36200959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlovmodule_init(gre_init); 36300959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlovmodule_exit(gre_exit); 36400959ade36acadc00e757f87060bf6e4501d545fDmitry Kozlov 36500959ade36acadc00e757f87060bf6e4501d545fDmitry KozlovMODULE_DESCRIPTION("GRE over IPv4 demultiplexer driver"); 36600959ade36acadc00e757f87060bf6e4501d545fDmitry KozlovMODULE_AUTHOR("D. Kozlov (xeb@mail.ru)"); 36700959ade36acadc00e757f87060bf6e4501d545fDmitry KozlovMODULE_LICENSE("GPL"); 368