Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  1 /*
  2  * ip_conntrack_proto_gre.c - Version 3.0
  3  *
  4  * Connection tracking protocol helper module for GRE.
  5  *
  6  * GRE is a generic encapsulation protocol, which is generally not very
  7  * suited for NAT, as it has no protocol-specific part as port numbers.
  8  *
  9  * It has an optional key field, which may help us distinguishing two
 10  * connections between the same two hosts.
 11  *
 12  * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784
 13  *
 14  * PPTP is built on top of a modified version of GRE, and has a mandatory
 15  * field called "CallID", which serves us for the same purpose as the key
 16  * field in plain GRE.
 17  *
 18  * Documentation about PPTP can be found in RFC 2637
 19  *
 20  * (C) 2000-2005 by Harald Welte <laforge@gnumonks.org>
 21  *
 22  * Development of this code funded by Astaro AG (http://www.astaro.com/)
 23  *
 24  */
 25 
 26 #include <linux/module.h>
 27 #include <linux/types.h>
 28 #include <linux/timer.h>
 29 #include <linux/list.h>
 30 #include <linux/seq_file.h>
 31 #include <linux/in.h>
 32 #include <linux/skbuff.h>
 33 
 34 #include <net/netfilter/nf_conntrack_l4proto.h>
 35 #include <net/netfilter/nf_conntrack_helper.h>
 36 #include <net/netfilter/nf_conntrack_core.h>
 37 #include <linux/netfilter/nf_conntrack_proto_gre.h>
 38 #include <linux/netfilter/nf_conntrack_pptp.h>
 39 
 40 #define GRE_TIMEOUT             (30 * HZ)
 41 #define GRE_STREAM_TIMEOUT      (180 * HZ)
 42 
 43 static DEFINE_RWLOCK(nf_ct_gre_lock);
 44 static LIST_HEAD(gre_keymap_list);
 45 
 46 void nf_ct_gre_keymap_flush(void)
 47 {
 48         struct list_head *pos, *n;
 49 
 50         write_lock_bh(&nf_ct_gre_lock);
 51         list_for_each_safe(pos, n, &gre_keymap_list) {
 52                 list_del(pos);
 53                 kfree(pos);
 54         }
 55         write_unlock_bh(&nf_ct_gre_lock);
 56 }
 57 EXPORT_SYMBOL(nf_ct_gre_keymap_flush);
 58 
 59 static inline int gre_key_cmpfn(const struct nf_ct_gre_keymap *km,
 60                                 const struct nf_conntrack_tuple *t)
 61 {
 62         return km->tuple.src.l3num == t->src.l3num &&
 63                !memcmp(&km->tuple.src.u3, &t->src.u3, sizeof(t->src.u3)) &&
 64                !memcmp(&km->tuple.dst.u3, &t->dst.u3, sizeof(t->dst.u3)) &&
 65                km->tuple.dst.protonum == t->dst.protonum &&
 66                km->tuple.dst.u.all == t->dst.u.all;
 67 }
 68 
 69 /* look up the source key for a given tuple */
 70 static __be16 gre_keymap_lookup(struct nf_conntrack_tuple *t)
 71 {
 72         struct nf_ct_gre_keymap *km;
 73         __be16 key = 0;
 74 
 75         read_lock_bh(&nf_ct_gre_lock);
 76         list_for_each_entry(km, &gre_keymap_list, list) {
 77                 if (gre_key_cmpfn(km, t)) {
 78                         key = km->tuple.src.u.gre.key;
 79                         break;
 80                 }
 81         }
 82         read_unlock_bh(&nf_ct_gre_lock);
 83 
 84         pr_debug("lookup src key 0x%x for ", key);
 85         NF_CT_DUMP_TUPLE(t);
 86 
 87         return key;
 88 }
 89 
 90 /* add a single keymap entry, associate with specified master ct */
 91 int nf_ct_gre_keymap_add(struct nf_conn *ct, enum ip_conntrack_dir dir,
 92                          struct nf_conntrack_tuple *t)
 93 {
 94         struct nf_conn_help *help = nfct_help(ct);
 95         struct nf_ct_gre_keymap **kmp, *km;
 96 
 97         kmp = &help->help.ct_pptp_info.keymap[dir];
 98         if (*kmp) {
 99                 /* check whether it's a retransmission */
100                 list_for_each_entry(km, &gre_keymap_list, list) {
101                         if (gre_key_cmpfn(km, t) && km == *kmp)
102                                 return 0;
103                 }
104                 pr_debug("trying to override keymap_%s for ct %p\n",
105                          dir == IP_CT_DIR_REPLY ? "reply" : "orig", ct);
106                 return -EEXIST;
107         }
108 
109         km = kmalloc(sizeof(*km), GFP_ATOMIC);
110         if (!km)
111                 return -ENOMEM;
112         memcpy(&km->tuple, t, sizeof(*t));
113         *kmp = km;
114 
115         pr_debug("adding new entry %p: ", km);
116         NF_CT_DUMP_TUPLE(&km->tuple);
117 
118         write_lock_bh(&nf_ct_gre_lock);
119         list_add_tail(&km->list, &gre_keymap_list);
120         write_unlock_bh(&nf_ct_gre_lock);
121 
122         return 0;
123 }
124 EXPORT_SYMBOL_GPL(nf_ct_gre_keymap_add);
125 
126 /* destroy the keymap entries associated with specified master ct */
127 void nf_ct_gre_keymap_destroy(struct nf_conn *ct)
128 {
129         struct nf_conn_help *help = nfct_help(ct);
130         enum ip_conntrack_dir dir;
131 
132         pr_debug("entering for ct %p\n", ct);
133 
134         write_lock_bh(&nf_ct_gre_lock);
135         for (dir = IP_CT_DIR_ORIGINAL; dir < IP_CT_DIR_MAX; dir++) {
136                 if (help->help.ct_pptp_info.keymap[dir]) {
137                         pr_debug("removing %p from list\n",
138                                  help->help.ct_pptp_info.keymap[dir]);
139                         list_del(&help->help.ct_pptp_info.keymap[dir]->list);
140                         kfree(help->help.ct_pptp_info.keymap[dir]);
141                         help->help.ct_pptp_info.keymap[dir] = NULL;
142                 }
143         }
144         write_unlock_bh(&nf_ct_gre_lock);
145 }
146 EXPORT_SYMBOL_GPL(nf_ct_gre_keymap_destroy);
147 
148 /* PUBLIC CONNTRACK PROTO HELPER FUNCTIONS */
149 
150 /* invert gre part of tuple */
151 static int gre_invert_tuple(struct nf_conntrack_tuple *tuple,
152                             const struct nf_conntrack_tuple *orig)
153 {
154         tuple->dst.u.gre.key = orig->src.u.gre.key;
155         tuple->src.u.gre.key = orig->dst.u.gre.key;
156         return 1;
157 }
158 
159 /* gre hdr info to tuple */
160 static int gre_pkt_to_tuple(const struct sk_buff *skb,
161                            unsigned int dataoff,
162                            struct nf_conntrack_tuple *tuple)
163 {
164         const struct gre_hdr_pptp *pgrehdr;
165         struct gre_hdr_pptp _pgrehdr;
166         __be16 srckey;
167         const struct gre_hdr *grehdr;
168         struct gre_hdr _grehdr;
169 
170         /* first only delinearize old RFC1701 GRE header */
171         grehdr = skb_header_pointer(skb, dataoff, sizeof(_grehdr), &_grehdr);
172         if (!grehdr || grehdr->version != GRE_VERSION_PPTP) {
173                 /* try to behave like "nf_conntrack_proto_generic" */
174                 tuple->src.u.all = 0;
175                 tuple->dst.u.all = 0;
176                 return 1;
177         }
178 
179         /* PPTP header is variable length, only need up to the call_id field */
180         pgrehdr = skb_header_pointer(skb, dataoff, 8, &_pgrehdr);
181         if (!pgrehdr)
182                 return 1;
183 
184         if (ntohs(grehdr->protocol) != GRE_PROTOCOL_PPTP) {
185                 pr_debug("GRE_VERSION_PPTP but unknown proto\n");
186                 return 0;
187         }
188 
189         tuple->dst.u.gre.key = pgrehdr->call_id;
190         srckey = gre_keymap_lookup(tuple);
191         tuple->src.u.gre.key = srckey;
192 
193         return 1;
194 }
195 
196 /* print gre part of tuple */
197 static int gre_print_tuple(struct seq_file *s,
198                            const struct nf_conntrack_tuple *tuple)
199 {
200         return seq_printf(s, "srckey=0x%x dstkey=0x%x ",
201                           ntohs(tuple->src.u.gre.key),
202                           ntohs(tuple->dst.u.gre.key));
203 }
204 
205 /* print private data for conntrack */
206 static int gre_print_conntrack(struct seq_file *s,
207                                const struct nf_conn *ct)
208 {
209         return seq_printf(s, "timeout=%u, stream_timeout=%u ",
210                           (ct->proto.gre.timeout / HZ),
211                           (ct->proto.gre.stream_timeout / HZ));
212 }
213 
214 /* Returns verdict for packet, and may modify conntrack */
215 static int gre_packet(struct nf_conn *ct,
216                       const struct sk_buff *skb,
217                       unsigned int dataoff,
218                       enum ip_conntrack_info ctinfo,
219                       int pf,
220                       unsigned int hooknum)
221 {
222         /* If we've seen traffic both ways, this is a GRE connection.
223          * Extend timeout. */
224         if (ct->status & IPS_SEEN_REPLY) {
225                 nf_ct_refresh_acct(ct, ctinfo, skb,
226                                    ct->proto.gre.stream_timeout);
227                 /* Also, more likely to be important, and not a probe. */
228                 set_bit(IPS_ASSURED_BIT, &ct->status);
229                 nf_conntrack_event_cache(IPCT_STATUS, skb);
230         } else
231                 nf_ct_refresh_acct(ct, ctinfo, skb,
232                                    ct->proto.gre.timeout);
233 
234         return NF_ACCEPT;
235 }
236 
237 /* Called when a new connection for this protocol found. */
238 static int gre_new(struct nf_conn *ct, const struct sk_buff *skb,
239                    unsigned int dataoff)
240 {
241         pr_debug(": ");
242         NF_CT_DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
243 
244         /* initialize to sane value.  Ideally a conntrack helper
245          * (e.g. in case of pptp) is increasing them */
246         ct->proto.gre.stream_timeout = GRE_STREAM_TIMEOUT;
247         ct->proto.gre.timeout = GRE_TIMEOUT;
248 
249         return 1;
250 }
251 
252 /* Called when a conntrack entry has already been removed from the hashes
253  * and is about to be deleted from memory */
254 static void gre_destroy(struct nf_conn *ct)
255 {
256         struct nf_conn *master = ct->master;
257         pr_debug(" entering\n");
258 
259         if (!master)
260                 pr_debug("no master !?!\n");
261         else
262                 nf_ct_gre_keymap_destroy(master);
263 }
264 
265 /* protocol helper struct */
266 static struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 __read_mostly = {
267         .l3proto         = AF_INET,
268         .l4proto         = IPPROTO_GRE,
269         .name            = "gre",
270         .pkt_to_tuple    = gre_pkt_to_tuple,
271         .invert_tuple    = gre_invert_tuple,
272         .print_tuple     = gre_print_tuple,
273         .print_conntrack = gre_print_conntrack,
274         .packet          = gre_packet,
275         .new             = gre_new,
276         .destroy         = gre_destroy,
277         .me              = THIS_MODULE,
278 #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
279         .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr,
280         .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple,
281         .nla_policy      = nf_ct_port_nla_policy,
282 #endif
283 };
284 
285 static int __init nf_ct_proto_gre_init(void)
286 {
287         return nf_conntrack_l4proto_register(&nf_conntrack_l4proto_gre4);
288 }
289 
290 static void nf_ct_proto_gre_fini(void)
291 {
292         nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_gre4);
293         nf_ct_gre_keymap_flush();
294 }
295 
296 module_init(nf_ct_proto_gre_init);
297 module_exit(nf_ct_proto_gre_fini);
298 
299 MODULE_LICENSE("GPL");
300 
  This page was automatically generated by the LXR engine.