This commit was manufactured by cvs2svn to create branch
[linux-2.6.git] / net / ipv4 / netfilter / ip_conntrack_pptp.c
1 /*
2  * ip_conntrack_pptp.c  - Version 2.0
3  *
4  * Connection tracking support for PPTP (Point to Point Tunneling Protocol).
5  * PPTP is a a protocol for creating virtual private networks.
6  * It is a specification defined by Microsoft and some vendors
7  * working with Microsoft.  PPTP is built on top of a modified
8  * version of the Internet Generic Routing Encapsulation Protocol.
9  * GRE is defined in RFC 1701 and RFC 1702.  Documentation of
10  * PPTP can be found in RFC 2637
11  *
12  * (C) 2000-2003 by Harald Welte <laforge@gnumonks.org>
13  *
14  * Development of this code funded by Astaro AG (http://www.astaro.com/)
15  *
16  * Limitations:
17  *       - We blindly assume that control connections are always
18  *         established in PNS->PAC direction.  This is a violation
19  *         of RFFC2673
20  *
21  * TODO: - finish support for multiple calls within one session
22  *         (needs expect reservations in newnat)
23  *       - testing of incoming PPTP calls 
24  *
25  * Changes: 
26  *      2002-02-05 - Version 1.3
27  *        - Call ip_conntrack_unexpect_related() from 
28  *          pptp_timeout_related() to destroy expectations in case
29  *          CALL_DISCONNECT_NOTIFY or tcp fin packet was seen
30  *          (Philip Craig <philipc@snapgear.com>)
31  *        - Add Version information at module loadtime
32  *      2002-02-10 - Version 1.6
33  *        - move to C99 style initializers
34  *        - remove second expectation if first arrives
35  *      2004-10-22 - Version 2.0
36  *        - merge Mandrake's 2.6.x port with recent 2.6.x API changes
37  *        - fix lots of linear skb assumptions from Mandrake's port
38  *
39  */
40
41 #include <linux/config.h>
42 #include <linux/module.h>
43 #include <linux/netfilter.h>
44 #include <linux/ip.h>
45 #include <net/checksum.h>
46 #include <net/tcp.h>
47
48 #include <linux/netfilter_ipv4/lockhelp.h>
49 #include <linux/netfilter_ipv4/ip_conntrack_helper.h>
50 #include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
51 #include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
52
53 #define IP_CT_PPTP_VERSION "2.0"
54
55 MODULE_LICENSE("GPL");
56 MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
57 MODULE_DESCRIPTION("Netfilter connection tracking helper module for PPTP");
58
59 DECLARE_LOCK(ip_pptp_lock);
60
61 #if 0
62 #include "ip_conntrack_pptp_priv.h"
63 #define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s: " format, __FILE__, __FUNCTION__, ## args)
64 #else
65 #define DEBUGP(format, args...)
66 #endif
67
68 #define SECS *HZ
69 #define MINS * 60 SECS
70 #define HOURS * 60 MINS
71 #define DAYS * 24 HOURS
72
73 #define PPTP_GRE_TIMEOUT                (10 MINS)
74 #define PPTP_GRE_STREAM_TIMEOUT         (5 DAYS)
75
76 static int pptp_expectfn(struct ip_conntrack *ct)
77 {
78         struct ip_conntrack *master;
79         struct ip_conntrack_expect *exp;
80
81         DEBUGP("increasing timeouts\n");
82         /* increase timeout of GRE data channel conntrack entry */
83         ct->proto.gre.timeout = PPTP_GRE_TIMEOUT;
84         ct->proto.gre.stream_timeout = PPTP_GRE_STREAM_TIMEOUT;
85
86         master = master_ct(ct);
87         if (!master) {
88                 DEBUGP(" no master!!!\n");
89                 return 0;
90         }
91
92         exp = ct->master;
93         if (!exp) {
94                 DEBUGP("no expectation!!\n");
95                 return 0;
96         }
97
98         DEBUGP("completing tuples with ct info\n");
99         /* we can do this, since we're unconfirmed */
100         if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key == 
101                 htonl(master->help.ct_pptp_info.pac_call_id)) { 
102                 /* assume PNS->PAC */
103                 ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key = 
104                         htonl(master->help.ct_pptp_info.pns_call_id);
105                 ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key =
106                         htonl(master->help.ct_pptp_info.pns_call_id);
107         } else {
108                 /* assume PAC->PNS */
109                 ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key =
110                         htonl(master->help.ct_pptp_info.pac_call_id);
111                 ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key =
112                         htonl(master->help.ct_pptp_info.pac_call_id);
113         }
114         
115         /* delete other expectation */
116         if (exp->expected_list.next != &exp->expected_list) {
117                 struct ip_conntrack_expect *other_exp;
118                 struct list_head *cur_item, *next;
119
120                 for (cur_item = master->sibling_list.next;
121                      cur_item != &master->sibling_list; cur_item = next) {
122                         next = cur_item->next;
123                         other_exp = list_entry(cur_item,
124                                                struct ip_conntrack_expect,
125                                                expected_list);
126                         /* remove only if occurred at same sequence number */
127                         if (other_exp != exp && other_exp->seq == exp->seq) {
128                                 DEBUGP("unexpecting other direction\n");
129                                 ip_ct_gre_keymap_destroy(other_exp);
130                                 ip_conntrack_unexpect_related(other_exp);
131                         }
132                 }
133         }
134
135         return 0;
136 }
137
138 /* timeout GRE data connections */
139 static int pptp_timeout_related(struct ip_conntrack *ct)
140 {
141         struct list_head *cur_item, *next;
142         struct ip_conntrack_expect *exp;
143
144         /* FIXME: do we have to lock something ? */
145         for (cur_item = ct->sibling_list.next;
146             cur_item != &ct->sibling_list; cur_item = next) {
147                 next = cur_item->next;
148                 exp = list_entry(cur_item, struct ip_conntrack_expect,
149                                  expected_list);
150
151                 ip_ct_gre_keymap_destroy(exp);
152                 if (!exp->sibling) {
153                         ip_conntrack_unexpect_related(exp);
154                         continue;
155                 }
156
157                 DEBUGP("setting timeout of conntrack %p to 0\n",
158                         exp->sibling);
159                 exp->sibling->proto.gre.timeout = 0;
160                 exp->sibling->proto.gre.stream_timeout = 0;
161                 /* refresh_acct will not modify counters if skb == NULL */
162                 ip_ct_refresh_acct(exp->sibling, 0, NULL, 0);
163         }
164
165         return 0;
166 }
167
168 /* expect GRE connections (PNS->PAC and PAC->PNS direction) */
169 static inline int
170 exp_gre(struct ip_conntrack *master,
171         u_int32_t seq,
172         u_int16_t callid,
173         u_int16_t peer_callid)
174 {
175         struct ip_conntrack_tuple inv_tuple;
176         struct ip_conntrack_tuple exp_tuples[] = {
177                 /* tuple in original direction, PNS->PAC */
178                 { .src = { .ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip,
179                            .u = { .gre = { .key = htonl(ntohs(peer_callid)) } }
180                          },
181                   .dst = { .ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip,
182                            .u = { .gre = { .key = htonl(ntohs(callid)) } },
183                            .protonum = IPPROTO_GRE
184                          },
185                  },
186                 /* tuple in reply direction, PAC->PNS */
187                 { .src = { .ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip,
188                            .u = { .gre = { .key = htonl(ntohs(callid)) } }
189                          },
190                   .dst = { .ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip,
191                            .u = { .gre = { .key = htonl(ntohs(peer_callid)) } },
192                            .protonum = IPPROTO_GRE
193                          },
194                  }
195         }, *exp_tuple;
196
197         for (exp_tuple = exp_tuples; exp_tuple < &exp_tuples[2]; exp_tuple++) {
198                 struct ip_conntrack_expect *exp;
199
200                 exp = ip_conntrack_expect_alloc();
201                 if (exp == NULL)
202                         return 1;
203
204                 memcpy(&exp->tuple, exp_tuple, sizeof(exp->tuple));
205
206                 exp->mask.src.ip = 0xffffffff;
207                 exp->mask.src.u.all = 0;
208                 exp->mask.dst.u.all = 0;
209                 exp->mask.dst.u.gre.key = 0xffffffff;
210                 exp->mask.dst.ip = 0xffffffff;
211                 exp->mask.dst.protonum = 0xffff;
212                         
213                 exp->seq = seq;
214                 exp->expectfn = pptp_expectfn;
215
216                 exp->help.exp_pptp_info.pac_call_id = ntohs(callid);
217                 exp->help.exp_pptp_info.pns_call_id = ntohs(peer_callid);
218
219                 DEBUGP("calling expect_related ");
220                 DUMP_TUPLE_RAW(&exp->tuple);
221         
222                 /* Add GRE keymap entries */
223                 if (ip_ct_gre_keymap_add(exp, &exp->tuple, 0) != 0) {
224                         kfree(exp);
225                         return 1;
226                 }
227
228                 invert_tuplepr(&inv_tuple, &exp->tuple);
229                 if (ip_ct_gre_keymap_add(exp, &inv_tuple, 1) != 0) {
230                         ip_ct_gre_keymap_destroy(exp);
231                         kfree(exp);
232                         return 1;
233                 }
234         
235                 if (ip_conntrack_expect_related(exp, master) != 0) {
236                         ip_ct_gre_keymap_destroy(exp);
237                         kfree(exp);
238                         DEBUGP("cannot expect_related()\n");
239                         return 1;
240                 }
241         }
242
243         return 0;
244 }
245
246 static inline int 
247 pptp_inbound_pkt(struct sk_buff *skb,
248                  struct tcphdr *tcph,
249                  unsigned int ctlhoff,
250                  size_t datalen,
251                  struct ip_conntrack *ct)
252 {
253         struct PptpControlHeader _ctlh, *ctlh;
254         unsigned int reqlen;
255         union pptp_ctrl_union _pptpReq, *pptpReq;
256         struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
257         u_int16_t msg, *cid, *pcid;
258         u_int32_t seq;  
259
260         ctlh = skb_header_pointer(skb, ctlhoff, sizeof(_ctlh), &_ctlh);
261         if (unlikely(!ctlh)) {
262                 DEBUGP("error during skb_header_pointer\n");
263                 return NF_ACCEPT;
264         }
265
266         reqlen = datalen - sizeof(struct pptp_pkt_hdr) - sizeof(_ctlh);
267         pptpReq = skb_header_pointer(skb, ctlhoff+sizeof(struct pptp_pkt_hdr),
268                                      reqlen, &_pptpReq);
269         if (unlikely(!pptpReq)) {
270                 DEBUGP("error during skb_header_pointer\n");
271                 return NF_ACCEPT;
272         }
273
274         msg = ntohs(ctlh->messageType);
275         DEBUGP("inbound control message %s\n", strMName[msg]);
276
277         switch (msg) {
278         case PPTP_START_SESSION_REPLY:
279                 if (reqlen < sizeof(_pptpReq.srep)) {
280                         DEBUGP("%s: short packet\n", strMName[msg]);
281                         break;
282                 }
283
284                 /* server confirms new control session */
285                 if (info->sstate < PPTP_SESSION_REQUESTED) {
286                         DEBUGP("%s without START_SESS_REQUEST\n",
287                                 strMName[msg]);
288                         break;
289                 }
290                 if (pptpReq->srep.resultCode == PPTP_START_OK)
291                         info->sstate = PPTP_SESSION_CONFIRMED;
292                 else 
293                         info->sstate = PPTP_SESSION_ERROR;
294                 break;
295
296         case PPTP_STOP_SESSION_REPLY:
297                 if (reqlen < sizeof(_pptpReq.strep)) {
298                         DEBUGP("%s: short packet\n", strMName[msg]);
299                         break;
300                 }
301
302                 /* server confirms end of control session */
303                 if (info->sstate > PPTP_SESSION_STOPREQ) {
304                         DEBUGP("%s without STOP_SESS_REQUEST\n",
305                                 strMName[msg]);
306                         break;
307                 }
308                 if (pptpReq->strep.resultCode == PPTP_STOP_OK)
309                         info->sstate = PPTP_SESSION_NONE;
310                 else
311                         info->sstate = PPTP_SESSION_ERROR;
312                 break;
313
314         case PPTP_OUT_CALL_REPLY:
315                 if (reqlen < sizeof(_pptpReq.ocack)) {
316                         DEBUGP("%s: short packet\n", strMName[msg]);
317                         break;
318                 }
319
320                 /* server accepted call, we now expect GRE frames */
321                 if (info->sstate != PPTP_SESSION_CONFIRMED) {
322                         DEBUGP("%s but no session\n", strMName[msg]);
323                         break;
324                 }
325                 if (info->cstate != PPTP_CALL_OUT_REQ &&
326                     info->cstate != PPTP_CALL_OUT_CONF) {
327                         DEBUGP("%s without OUTCALL_REQ\n", strMName[msg]);
328                         break;
329                 }
330                 if (pptpReq->ocack.resultCode != PPTP_OUTCALL_CONNECT) {
331                         info->cstate = PPTP_CALL_NONE;
332                         break;
333                 }
334
335                 cid = &pptpReq->ocack.callID;
336                 pcid = &pptpReq->ocack.peersCallID;
337
338                 info->pac_call_id = ntohs(*cid);
339                 
340                 if (htons(info->pns_call_id) != *pcid) {
341                         DEBUGP("%s for unknown callid %u\n",
342                                 strMName[msg], ntohs(*pcid));
343                         break;
344                 }
345
346                 DEBUGP("%s, CID=%X, PCID=%X\n", strMName[msg], 
347                         ntohs(*cid), ntohs(*pcid));
348                 
349                 info->cstate = PPTP_CALL_OUT_CONF;
350
351                 seq = ntohl(tcph->seq) + sizeof(struct pptp_pkt_hdr)
352                                        + sizeof(struct PptpControlHeader)
353                                        + ((void *)pcid - (void *)pptpReq);
354                         
355                 if (exp_gre(ct, seq, *cid, *pcid) != 0)
356                         printk("ip_conntrack_pptp: error during exp_gre\n");
357                 break;
358
359         case PPTP_IN_CALL_REQUEST:
360                 if (reqlen < sizeof(_pptpReq.icack)) {
361                         DEBUGP("%s: short packet\n", strMName[msg]);
362                         break;
363                 }
364
365                 /* server tells us about incoming call request */
366                 if (info->sstate != PPTP_SESSION_CONFIRMED) {
367                         DEBUGP("%s but no session\n", strMName[msg]);
368                         break;
369                 }
370                 pcid = &pptpReq->icack.peersCallID;
371                 DEBUGP("%s, PCID=%X\n", strMName[msg], ntohs(*pcid));
372                 info->cstate = PPTP_CALL_IN_REQ;
373                 info->pac_call_id = ntohs(*pcid);
374                 break;
375
376         case PPTP_IN_CALL_CONNECT:
377                 if (reqlen < sizeof(_pptpReq.iccon)) {
378                         DEBUGP("%s: short packet\n", strMName[msg]);
379                         break;
380                 }
381
382                 /* server tells us about incoming call established */
383                 if (info->sstate != PPTP_SESSION_CONFIRMED) {
384                         DEBUGP("%s but no session\n", strMName[msg]);
385                         break;
386                 }
387                 if (info->sstate != PPTP_CALL_IN_REP
388                     && info->sstate != PPTP_CALL_IN_CONF) {
389                         DEBUGP("%s but never sent IN_CALL_REPLY\n",
390                                 strMName[msg]);
391                         break;
392                 }
393
394                 pcid = &pptpReq->iccon.peersCallID;
395                 cid = &info->pac_call_id;
396
397                 if (info->pns_call_id != ntohs(*pcid)) {
398                         DEBUGP("%s for unknown CallID %u\n", 
399                                 strMName[msg], ntohs(*cid));
400                         break;
401                 }
402
403                 DEBUGP("%s, PCID=%X\n", strMName[msg], ntohs(*pcid));
404                 info->cstate = PPTP_CALL_IN_CONF;
405
406                 /* we expect a GRE connection from PAC to PNS */
407                 seq = ntohl(tcph->seq) + sizeof(struct pptp_pkt_hdr)
408                                        + sizeof(struct PptpControlHeader)
409                                        + ((void *)pcid - (void *)pptpReq);
410                         
411                 if (exp_gre(ct, seq, *cid, *pcid) != 0)
412                         printk("ip_conntrack_pptp: error during exp_gre\n");
413
414                 break;
415
416         case PPTP_CALL_DISCONNECT_NOTIFY:
417                 if (reqlen < sizeof(_pptpReq.disc)) {
418                         DEBUGP("%s: short packet\n", strMName[msg]);
419                         break;
420                 }
421
422                 /* server confirms disconnect */
423                 cid = &pptpReq->disc.callID;
424                 DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*cid));
425                 info->cstate = PPTP_CALL_NONE;
426
427                 /* untrack this call id, unexpect GRE packets */
428                 pptp_timeout_related(ct);
429                 break;
430
431         case PPTP_WAN_ERROR_NOTIFY:
432                 break;
433
434         case PPTP_ECHO_REQUEST:
435         case PPTP_ECHO_REPLY:
436                 /* I don't have to explain these ;) */
437                 break;
438         default:
439                 DEBUGP("invalid %s (TY=%d)\n", (msg <= PPTP_MSG_MAX)
440                         ? strMName[msg]:strMName[0], msg);
441                 break;
442         }
443
444         return NF_ACCEPT;
445
446 }
447
448 static inline int
449 pptp_outbound_pkt(struct sk_buff *skb,
450                   struct tcphdr *tcph,
451                   unsigned int ctlhoff,
452                   size_t datalen,
453                   struct ip_conntrack *ct)
454 {
455         struct PptpControlHeader _ctlh, *ctlh;
456         unsigned int reqlen;
457         union pptp_ctrl_union _pptpReq, *pptpReq;
458         struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
459         u_int16_t msg, *cid, *pcid;
460
461         ctlh = skb_header_pointer(skb, ctlhoff, sizeof(_ctlh), &_ctlh);
462         if (!ctlh)
463                 return NF_ACCEPT;
464         
465         reqlen = datalen - sizeof(struct pptp_pkt_hdr) - sizeof(_ctlh);
466         pptpReq = skb_header_pointer(skb, ctlhoff+sizeof(_ctlh), reqlen, 
467                                      &_pptpReq);
468         if (!pptpReq)
469                 return NF_ACCEPT;
470
471         msg = ntohs(ctlh->messageType);
472         DEBUGP("outbound control message %s\n", strMName[msg]);
473
474         switch (msg) {
475         case PPTP_START_SESSION_REQUEST:
476                 /* client requests for new control session */
477                 if (info->sstate != PPTP_SESSION_NONE) {
478                         DEBUGP("%s but we already have one",
479                                 strMName[msg]);
480                 }
481                 info->sstate = PPTP_SESSION_REQUESTED;
482                 break;
483         case PPTP_STOP_SESSION_REQUEST:
484                 /* client requests end of control session */
485                 info->sstate = PPTP_SESSION_STOPREQ;
486                 break;
487
488         case PPTP_OUT_CALL_REQUEST:
489                 if (reqlen < sizeof(_pptpReq.ocreq)) {
490                         DEBUGP("%s: short packet\n", strMName[msg]);
491                         break;
492                 }
493
494                 /* client initiating connection to server */
495                 if (info->sstate != PPTP_SESSION_CONFIRMED) {
496                         DEBUGP("%s but no session\n",
497                                 strMName[msg]);
498                         break;
499                 }
500                 info->cstate = PPTP_CALL_OUT_REQ;
501                 /* track PNS call id */
502                 cid = &pptpReq->ocreq.callID;
503                 DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*cid));
504                 info->pns_call_id = ntohs(*cid);
505                 break;
506         case PPTP_IN_CALL_REPLY:
507                 if (reqlen < sizeof(_pptpReq.icack)) {
508                         DEBUGP("%s: short packet\n", strMName[msg]);
509                         break;
510                 }
511
512                 /* client answers incoming call */
513                 if (info->cstate != PPTP_CALL_IN_REQ
514                     && info->cstate != PPTP_CALL_IN_REP) {
515                         DEBUGP("%s without incall_req\n", 
516                                 strMName[msg]);
517                         break;
518                 }
519                 if (pptpReq->icack.resultCode != PPTP_INCALL_ACCEPT) {
520                         info->cstate = PPTP_CALL_NONE;
521                         break;
522                 }
523                 pcid = &pptpReq->icack.peersCallID;
524                 if (info->pac_call_id != ntohs(*pcid)) {
525                         DEBUGP("%s for unknown call %u\n", 
526                                 strMName[msg], ntohs(*pcid));
527                         break;
528                 }
529                 DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*pcid));
530                 /* part two of the three-way handshake */
531                 info->cstate = PPTP_CALL_IN_REP;
532                 info->pns_call_id = ntohs(pptpReq->icack.callID);
533                 break;
534
535         case PPTP_CALL_CLEAR_REQUEST:
536                 /* client requests hangup of call */
537                 if (info->sstate != PPTP_SESSION_CONFIRMED) {
538                         DEBUGP("CLEAR_CALL but no session\n");
539                         break;
540                 }
541                 /* FUTURE: iterate over all calls and check if
542                  * call ID is valid.  We don't do this without newnat,
543                  * because we only know about last call */
544                 info->cstate = PPTP_CALL_CLEAR_REQ;
545                 break;
546         case PPTP_SET_LINK_INFO:
547                 break;
548         case PPTP_ECHO_REQUEST:
549         case PPTP_ECHO_REPLY:
550                 /* I don't have to explain these ;) */
551                 break;
552         default:
553                 DEBUGP("invalid %s (TY=%d)\n", (msg <= PPTP_MSG_MAX)? 
554                         strMName[msg]:strMName[0], msg);
555                 /* unknown: no need to create GRE masq table entry */
556                 break;
557         }
558
559         return NF_ACCEPT;
560 }
561
562
563 /* track caller id inside control connection, call expect_related */
564 static int 
565 conntrack_pptp_help(struct sk_buff *skb,
566                     struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
567
568 {
569         struct pptp_pkt_hdr _pptph, *pptph;
570         
571         struct tcphdr _tcph, *tcph;
572         u_int32_t tcplen = skb->len - skb->nh.iph->ihl * 4;
573         u_int32_t datalen;
574         void *datalimit;
575         int dir = CTINFO2DIR(ctinfo);
576         struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
577         unsigned int nexthdr_off;
578
579         int oldsstate, oldcstate;
580         int ret;
581
582         /* don't do any tracking before tcp handshake complete */
583         if (ctinfo != IP_CT_ESTABLISHED 
584             && ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY) {
585                 DEBUGP("ctinfo = %u, skipping\n", ctinfo);
586                 return NF_ACCEPT;
587         }
588         
589         nexthdr_off = skb->nh.iph->ihl*4;
590         tcph = skb_header_pointer(skb, skb->nh.iph->ihl*4, sizeof(_tcph),
591                                   &_tcph);
592         if (!tcph)
593                 return NF_ACCEPT;
594
595         /* not a complete TCP header? */
596         if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) {
597                 DEBUGP("tcplen = %u\n", tcplen);
598                 return NF_ACCEPT;
599         }
600
601
602         datalen = tcplen - tcph->doff * 4;
603
604         /* checksum invalid? */
605         if (tcp_v4_check(tcph, tcplen, skb->nh.iph->saddr, skb->nh.iph->daddr,
606                         csum_partial((char *) tcph, tcplen, 0))) {
607                 printk(KERN_NOTICE __FILE__ ": bad csum\n");
608                 /* W2K PPTP server sends TCP packets with wrong checksum :(( */
609                 //return NF_ACCEPT;
610         }
611
612         if (tcph->fin || tcph->rst) {
613                 DEBUGP("RST/FIN received, timeouting GRE\n");
614                 /* can't do this after real newnat */
615                 info->cstate = PPTP_CALL_NONE;
616
617                 /* untrack this call id, unexpect GRE packets */
618                 pptp_timeout_related(ct);
619         }
620
621         nexthdr_off += tcph->doff*4;
622         pptph = skb_header_pointer(skb, skb->nh.iph->ihl*4 + tcph->doff*4,
623                                    sizeof(_pptph), &_pptph);
624         if (!pptph) {
625                 DEBUGP("no full PPTP header, can't track\n");
626                 return NF_ACCEPT;
627         }
628
629         datalimit = (void *) pptph + datalen;
630
631         /* if it's not a control message we can't do anything with it */
632         if (ntohs(pptph->packetType) != PPTP_PACKET_CONTROL ||
633             ntohl(pptph->magicCookie) != PPTP_MAGIC_COOKIE) {
634                 DEBUGP("not a control packet\n");
635                 return NF_ACCEPT;
636         }
637
638         oldsstate = info->sstate;
639         oldcstate = info->cstate;
640
641         LOCK_BH(&ip_pptp_lock);
642
643         nexthdr_off += sizeof(_pptph);
644         /* FIXME: We just blindly assume that the control connection is always
645          * established from PNS->PAC.  However, RFC makes no guarantee */
646         if (dir == IP_CT_DIR_ORIGINAL)
647                 /* client -> server (PNS -> PAC) */
648                 ret = pptp_outbound_pkt(skb, tcph, nexthdr_off, datalen, ct);
649         else
650                 /* server -> client (PAC -> PNS) */
651                 ret = pptp_inbound_pkt(skb, tcph, nexthdr_off, datalen, ct);
652         DEBUGP("sstate: %d->%d, cstate: %d->%d\n",
653                 oldsstate, info->sstate, oldcstate, info->cstate);
654         UNLOCK_BH(&ip_pptp_lock);
655
656         return ret;
657 }
658
659 /* control protocol helper */
660 static struct ip_conntrack_helper pptp = { 
661         .list = { NULL, NULL },
662         .name = "pptp", 
663         .flags = IP_CT_HELPER_F_REUSE_EXPECT,
664         .me = THIS_MODULE,
665         .max_expected = 2,
666         .timeout = 0,
667         .tuple = { .src = { .ip = 0, 
668                             .u = { .tcp = { .port =  
669                                     __constant_htons(PPTP_CONTROL_PORT) } } 
670                           }, 
671                    .dst = { .ip = 0, 
672                             .u = { .all = 0 },
673                             .protonum = IPPROTO_TCP
674                           } 
675                  },
676         .mask = { .src = { .ip = 0, 
677                            .u = { .tcp = { .port = 0xffff } } 
678                          }, 
679                   .dst = { .ip = 0, 
680                            .u = { .all = 0 },
681                            .protonum = 0xffff 
682                          } 
683                 },
684         .help = conntrack_pptp_help
685 };
686
687 /* ip_conntrack_pptp initialization */
688 static int __init init(void)
689 {
690         int retcode;
691
692         DEBUGP(__FILE__ ": registering helper\n");
693         if ((retcode = ip_conntrack_helper_register(&pptp))) {
694                 printk(KERN_ERR "Unable to register conntrack application "
695                                 "helper for pptp: %d\n", retcode);
696                 return -EIO;
697         }
698
699         printk("ip_conntrack_pptp version %s loaded\n", IP_CT_PPTP_VERSION);
700         return 0;
701 }
702
703 static void __exit fini(void)
704 {
705         ip_conntrack_helper_unregister(&pptp);
706         printk("ip_conntrack_pptp version %s unloaded\n", IP_CT_PPTP_VERSION);
707 }
708
709 module_init(init);
710 module_exit(fini);
711
712 EXPORT_SYMBOL(ip_pptp_lock);