Blame view
net/ipv4/gre_demux.c
4.31 KB
00959ade3 PPTP: PPP over IP... |
1 2 3 4 5 6 7 8 9 10 11 |
/* * GRE over IPv4 demultiplexer driver * * Authors: Dmitry Kozlov (xeb@mail.ru) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * */ |
afd465030 net: ipv4: Standa... |
12 |
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
00959ade3 PPTP: PPP over IP... |
13 |
#include <linux/module.h> |
bda7bb463 gre: Allow multip... |
14 15 |
#include <linux/if.h> #include <linux/icmp.h> |
00959ade3 PPTP: PPP over IP... |
16 17 18 19 |
#include <linux/kernel.h> #include <linux/kmod.h> #include <linux/skbuff.h> #include <linux/in.h> |
559fafb94 gre: fix improper... |
20 |
#include <linux/ip.h> |
00959ade3 PPTP: PPP over IP... |
21 |
#include <linux/netdevice.h> |
68c331631 v4 GRE: Add TCP s... |
22 |
#include <linux/if_tunnel.h> |
00959ade3 PPTP: PPP over IP... |
23 24 25 |
#include <linux/spinlock.h> #include <net/protocol.h> #include <net/gre.h> |
bda7bb463 gre: Allow multip... |
26 27 28 |
#include <net/icmp.h> #include <net/route.h> #include <net/xfrm.h> |
00959ade3 PPTP: PPP over IP... |
29 |
|
6f0bcf152 tunnels: add _rcu... |
30 |
static const struct gre_protocol __rcu *gre_proto[GREPROTO_MAX] __read_mostly; |
00959ade3 PPTP: PPP over IP... |
31 32 33 34 |
int gre_add_protocol(const struct gre_protocol *proto, u8 version) { if (version >= GREPROTO_MAX) |
20fd4d1f0 gre: Simplify gre... |
35 |
return -EINVAL; |
00959ade3 PPTP: PPP over IP... |
36 |
|
20fd4d1f0 gre: Simplify gre... |
37 38 |
return (cmpxchg((const struct gre_protocol **)&gre_proto[version], NULL, proto) == NULL) ? 0 : -EBUSY; |
00959ade3 PPTP: PPP over IP... |
39 40 41 42 43 |
} EXPORT_SYMBOL_GPL(gre_add_protocol); int gre_del_protocol(const struct gre_protocol *proto, u8 version) { |
20fd4d1f0 gre: Simplify gre... |
44 |
int ret; |
00959ade3 PPTP: PPP over IP... |
45 |
if (version >= GREPROTO_MAX) |
20fd4d1f0 gre: Simplify gre... |
46 47 48 49 50 51 52 |
return -EINVAL; ret = (cmpxchg((const struct gre_protocol **)&gre_proto[version], proto, NULL) == proto) ? 0 : -EBUSY; if (ret) return ret; |
00959ade3 PPTP: PPP over IP... |
53 54 |
synchronize_rcu(); return 0; |
00959ade3 PPTP: PPP over IP... |
55 56 |
} EXPORT_SYMBOL_GPL(gre_del_protocol); |
f132ae7c4 gre: change gre_p... |
57 |
/* Fills in tpi and returns header length to be pulled. */ |
95f5c64c3 gre: Move utility... |
58 |
int gre_parse_header(struct sk_buff *skb, struct tnl_ptk_info *tpi, |
e582615ad gre: fix error ha... |
59 |
bool *csum_err, __be16 proto, int nhs) |
95f5c64c3 gre: Move utility... |
60 61 62 63 |
{ const struct gre_base_hdr *greh; __be32 *options; int hdr_len; |
e582615ad gre: fix error ha... |
64 |
if (unlikely(!pskb_may_pull(skb, nhs + sizeof(struct gre_base_hdr)))) |
95f5c64c3 gre: Move utility... |
65 |
return -EINVAL; |
e582615ad gre: fix error ha... |
66 |
greh = (struct gre_base_hdr *)(skb->data + nhs); |
95f5c64c3 gre: Move utility... |
67 68 69 70 71 |
if (unlikely(greh->flags & (GRE_VERSION | GRE_ROUTING))) return -EINVAL; tpi->flags = gre_flags_to_tnl_flags(greh->flags); hdr_len = gre_calc_hlen(tpi->flags); |
e582615ad gre: fix error ha... |
72 |
if (!pskb_may_pull(skb, nhs + hdr_len)) |
95f5c64c3 gre: Move utility... |
73 |
return -EINVAL; |
e582615ad gre: fix error ha... |
74 |
greh = (struct gre_base_hdr *)(skb->data + nhs); |
95f5c64c3 gre: Move utility... |
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
tpi->proto = greh->protocol; options = (__be32 *)(greh + 1); if (greh->flags & GRE_CSUM) { if (skb_checksum_simple_validate(skb)) { *csum_err = true; return -EINVAL; } skb_checksum_try_convert(skb, IPPROTO_GRE, 0, null_compute_pseudo); options++; } if (greh->flags & GRE_KEY) { tpi->key = *options; options++; } else { tpi->key = 0; } if (unlikely(greh->flags & GRE_SEQ)) { tpi->seq = *options; options++; } else { tpi->seq = 0; } /* WCCP version 1 and 2 protocol decoding. |
da73b4e95 gre: Fix wrong tp... |
102 |
* - Change protocol to IPv4/IPv6 |
95f5c64c3 gre: Move utility... |
103 104 105 |
* - When dealing with WCCPv2, Skip extra 4 bytes in GRE header */ if (greh->flags == 0 && tpi->proto == htons(ETH_P_WCCP)) { |
da73b4e95 gre: Fix wrong tp... |
106 |
tpi->proto = proto; |
00b203402 gre: remove super... |
107 |
if ((*(u8 *)options & 0xF0) != 0x40) |
95f5c64c3 gre: Move utility... |
108 |
hdr_len += 4; |
95f5c64c3 gre: Move utility... |
109 |
} |
9b8c6d7bf gre: better suppo... |
110 |
tpi->hdr_len = hdr_len; |
f132ae7c4 gre: change gre_p... |
111 |
return hdr_len; |
95f5c64c3 gre: Move utility... |
112 113 |
} EXPORT_SYMBOL(gre_parse_header); |
00959ade3 PPTP: PPP over IP... |
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
static int gre_rcv(struct sk_buff *skb) { const struct gre_protocol *proto; u8 ver; int ret; if (!pskb_may_pull(skb, 12)) goto drop; ver = skb->data[1]&0x7f; if (ver >= GREPROTO_MAX) goto drop; rcu_read_lock(); proto = rcu_dereference(gre_proto[ver]); if (!proto || !proto->handler) goto drop_unlock; ret = proto->handler(skb); rcu_read_unlock(); return ret; drop_unlock: rcu_read_unlock(); drop: kfree_skb(skb); return NET_RX_DROP; } static void gre_err(struct sk_buff *skb, u32 info) { const struct gre_protocol *proto; |
559fafb94 gre: fix improper... |
145 146 |
const struct iphdr *iph = (const struct iphdr *)skb->data; u8 ver = skb->data[(iph->ihl<<2) + 1]&0x7f; |
00959ade3 PPTP: PPP over IP... |
147 |
|
00959ade3 PPTP: PPP over IP... |
148 |
if (ver >= GREPROTO_MAX) |
559fafb94 gre: fix improper... |
149 |
return; |
00959ade3 PPTP: PPP over IP... |
150 151 152 |
rcu_read_lock(); proto = rcu_dereference(gre_proto[ver]); |
559fafb94 gre: fix improper... |
153 154 |
if (proto && proto->err_handler) proto->err_handler(skb, info); |
00959ade3 PPTP: PPP over IP... |
155 |
rcu_read_unlock(); |
00959ade3 PPTP: PPP over IP... |
156 157 158 159 160 161 162 163 164 165 |
} static const struct net_protocol net_gre_protocol = { .handler = gre_rcv, .err_handler = gre_err, .netns_ok = 1, }; static int __init gre_init(void) { |
afd465030 net: ipv4: Standa... |
166 167 |
pr_info("GRE over IPv4 demultiplexor driver "); |
00959ade3 PPTP: PPP over IP... |
168 169 |
if (inet_add_protocol(&net_gre_protocol, IPPROTO_GRE) < 0) { |
afd465030 net: ipv4: Standa... |
170 171 |
pr_err("can't add protocol "); |
9f57c67c3 gre: Remove suppo... |
172 |
return -EAGAIN; |
bda7bb463 gre: Allow multip... |
173 |
} |
00959ade3 PPTP: PPP over IP... |
174 175 176 177 178 179 180 181 182 183 184 185 186 187 |
return 0; } static void __exit gre_exit(void) { inet_del_protocol(&net_gre_protocol, IPPROTO_GRE); } module_init(gre_init); module_exit(gre_exit); MODULE_DESCRIPTION("GRE over IPv4 demultiplexer driver"); MODULE_AUTHOR("D. Kozlov (xeb@mail.ru)"); MODULE_LICENSE("GPL"); |