Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
[sfrench/cifs-2.6.git] / net / ipv4 / netfilter / nf_nat_h323.c
1 /*
2  * H.323 extension for NAT alteration.
3  *
4  * Copyright (c) 2006 Jing Min Zhao <zhaojingmin@users.sourceforge.net>
5  *
6  * This source code is licensed under General Public License version 2.
7  *
8  * Based on the 'brute force' H.323 NAT module by
9  * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
10  */
11
12 #include <linux/module.h>
13 #include <linux/moduleparam.h>
14 #include <linux/tcp.h>
15 #include <net/tcp.h>
16
17 #include <net/netfilter/nf_nat.h>
18 #include <net/netfilter/nf_nat_helper.h>
19 #include <net/netfilter/nf_nat_rule.h>
20 #include <net/netfilter/nf_conntrack_helper.h>
21 #include <net/netfilter/nf_conntrack_expect.h>
22 #include <linux/netfilter/nf_conntrack_h323.h>
23
24 #if 0
25 #define DEBUGP printk
26 #else
27 #define DEBUGP(format, args...)
28 #endif
29
30 /****************************************************************************/
31 static int set_addr(struct sk_buff **pskb,
32                     unsigned char **data, int dataoff,
33                     unsigned int addroff, __be32 ip, __be16 port)
34 {
35         enum ip_conntrack_info ctinfo;
36         struct nf_conn *ct = ip_conntrack_get(*pskb, &ctinfo);
37         struct {
38                 __be32 ip;
39                 __be16 port;
40         } __attribute__ ((__packed__)) buf;
41         struct tcphdr _tcph, *th;
42
43         buf.ip = ip;
44         buf.port = port;
45         addroff += dataoff;
46
47         if ((*pskb)->nh.iph->protocol == IPPROTO_TCP) {
48                 if (!nf_nat_mangle_tcp_packet(pskb, ct, ctinfo,
49                                               addroff, sizeof(buf),
50                                               (char *) &buf, sizeof(buf))) {
51                         if (net_ratelimit())
52                                 printk("nf_nat_h323: nf_nat_mangle_tcp_packet"
53                                        " error\n");
54                         return -1;
55                 }
56
57                 /* Relocate data pointer */
58                 th = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl * 4,
59                                         sizeof(_tcph), &_tcph);
60                 if (th == NULL)
61                         return -1;
62                 *data = (*pskb)->data + (*pskb)->nh.iph->ihl * 4 +
63                     th->doff * 4 + dataoff;
64         } else {
65                 if (!nf_nat_mangle_udp_packet(pskb, ct, ctinfo,
66                                               addroff, sizeof(buf),
67                                               (char *) &buf, sizeof(buf))) {
68                         if (net_ratelimit())
69                                 printk("nf_nat_h323: nf_nat_mangle_udp_packet"
70                                        " error\n");
71                         return -1;
72                 }
73                 /* nf_nat_mangle_udp_packet uses skb_make_writable() to copy
74                  * or pull everything in a linear buffer, so we can safely
75                  * use the skb pointers now */
76                 *data = (*pskb)->data + (*pskb)->nh.iph->ihl * 4 +
77                     sizeof(struct udphdr);
78         }
79
80         return 0;
81 }
82
83 /****************************************************************************/
84 static int set_h225_addr(struct sk_buff **pskb,
85                          unsigned char **data, int dataoff,
86                          TransportAddress *taddr,
87                          union nf_conntrack_address *addr, __be16 port)
88 {
89         return set_addr(pskb, data, dataoff, taddr->ipAddress.ip,
90                         addr->ip, port);
91 }
92
93 /****************************************************************************/
94 static int set_h245_addr(struct sk_buff **pskb,
95                          unsigned char **data, int dataoff,
96                          H245_TransportAddress *taddr,
97                          union nf_conntrack_address *addr, __be16 port)
98 {
99         return set_addr(pskb, data, dataoff,
100                         taddr->unicastAddress.iPAddress.network,
101                         addr->ip, port);
102 }
103
104 /****************************************************************************/
105 static int set_sig_addr(struct sk_buff **pskb, struct nf_conn *ct,
106                         enum ip_conntrack_info ctinfo,
107                         unsigned char **data,
108                         TransportAddress *taddr, int count)
109 {
110         struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info;
111         int dir = CTINFO2DIR(ctinfo);
112         int i;
113         __be16 port;
114         union nf_conntrack_address addr;
115
116         for (i = 0; i < count; i++) {
117                 if (get_h225_addr(ct, *data, &taddr[i], &addr, &port)) {
118                         if (addr.ip == ct->tuplehash[dir].tuple.src.u3.ip &&
119                             port == info->sig_port[dir]) {
120                                 /* GW->GK */
121
122                                 /* Fix for Gnomemeeting */
123                                 if (i > 0 &&
124                                     get_h225_addr(ct, *data, &taddr[0],
125                                                   &addr, &port) &&
126                                     (ntohl(addr.ip) & 0xff000000) == 0x7f000000)
127                                         i = 0;
128
129                                 DEBUGP
130                                     ("nf_nat_ras: set signal address "
131                                      "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
132                                      NIPQUAD(ip), port,
133                                      NIPQUAD(ct->tuplehash[!dir].tuple.dst.
134                                              ip), info->sig_port[!dir]);
135                                 return set_h225_addr(pskb, data, 0, &taddr[i],
136                                                      &ct->tuplehash[!dir].
137                                                      tuple.dst.u3,
138                                                      info->sig_port[!dir]);
139                         } else if (addr.ip == ct->tuplehash[dir].tuple.dst.u3.ip &&
140                                    port == info->sig_port[dir]) {
141                                 /* GK->GW */
142                                 DEBUGP
143                                     ("nf_nat_ras: set signal address "
144                                      "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
145                                      NIPQUAD(ip), port,
146                                      NIPQUAD(ct->tuplehash[!dir].tuple.src.
147                                              ip), info->sig_port[!dir]);
148                                 return set_h225_addr(pskb, data, 0, &taddr[i],
149                                                      &ct->tuplehash[!dir].
150                                                      tuple.src.u3,
151                                                      info->sig_port[!dir]);
152                         }
153                 }
154         }
155
156         return 0;
157 }
158
159 /****************************************************************************/
160 static int set_ras_addr(struct sk_buff **pskb, struct nf_conn *ct,
161                         enum ip_conntrack_info ctinfo,
162                         unsigned char **data,
163                         TransportAddress *taddr, int count)
164 {
165         int dir = CTINFO2DIR(ctinfo);
166         int i;
167         __be16 port;
168         union nf_conntrack_address addr;
169
170         for (i = 0; i < count; i++) {
171                 if (get_h225_addr(ct, *data, &taddr[i], &addr, &port) &&
172                     addr.ip == ct->tuplehash[dir].tuple.src.u3.ip &&
173                     port == ct->tuplehash[dir].tuple.src.u.udp.port) {
174                         DEBUGP("nf_nat_ras: set rasAddress "
175                                "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
176                                NIPQUAD(ip), ntohs(port),
177                                NIPQUAD(ct->tuplehash[!dir].tuple.dst.u3.ip),
178                                ntohs(ct->tuplehash[!dir].tuple.dst.u.udp.
179                                      port));
180                         return set_h225_addr(pskb, data, 0, &taddr[i],
181                                              &ct->tuplehash[!dir].tuple.dst.u3,
182                                              ct->tuplehash[!dir].tuple.
183                                                                 dst.u.udp.port);
184                 }
185         }
186
187         return 0;
188 }
189
190 /****************************************************************************/
191 static int nat_rtp_rtcp(struct sk_buff **pskb, struct nf_conn *ct,
192                         enum ip_conntrack_info ctinfo,
193                         unsigned char **data, int dataoff,
194                         H245_TransportAddress *taddr,
195                         __be16 port, __be16 rtp_port,
196                         struct nf_conntrack_expect *rtp_exp,
197                         struct nf_conntrack_expect *rtcp_exp)
198 {
199         struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info;
200         int dir = CTINFO2DIR(ctinfo);
201         int i;
202         u_int16_t nated_port;
203
204         /* Set expectations for NAT */
205         rtp_exp->saved_proto.udp.port = rtp_exp->tuple.dst.u.udp.port;
206         rtp_exp->expectfn = nf_nat_follow_master;
207         rtp_exp->dir = !dir;
208         rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port;
209         rtcp_exp->expectfn = nf_nat_follow_master;
210         rtcp_exp->dir = !dir;
211
212         /* Lookup existing expects */
213         for (i = 0; i < H323_RTP_CHANNEL_MAX; i++) {
214                 if (info->rtp_port[i][dir] == rtp_port) {
215                         /* Expected */
216
217                         /* Use allocated ports first. This will refresh
218                          * the expects */
219                         rtp_exp->tuple.dst.u.udp.port = info->rtp_port[i][dir];
220                         rtcp_exp->tuple.dst.u.udp.port =
221                             htons(ntohs(info->rtp_port[i][dir]) + 1);
222                         break;
223                 } else if (info->rtp_port[i][dir] == 0) {
224                         /* Not expected */
225                         break;
226                 }
227         }
228
229         /* Run out of expectations */
230         if (i >= H323_RTP_CHANNEL_MAX) {
231                 if (net_ratelimit())
232                         printk("nf_nat_h323: out of expectations\n");
233                 return 0;
234         }
235
236         /* Try to get a pair of ports. */
237         for (nated_port = ntohs(rtp_exp->tuple.dst.u.udp.port);
238              nated_port != 0; nated_port += 2) {
239                 rtp_exp->tuple.dst.u.udp.port = htons(nated_port);
240                 if (nf_conntrack_expect_related(rtp_exp) == 0) {
241                         rtcp_exp->tuple.dst.u.udp.port =
242                             htons(nated_port + 1);
243                         if (nf_conntrack_expect_related(rtcp_exp) == 0)
244                                 break;
245                         nf_conntrack_unexpect_related(rtp_exp);
246                 }
247         }
248
249         if (nated_port == 0) {  /* No port available */
250                 if (net_ratelimit())
251                         printk("nf_nat_h323: out of RTP ports\n");
252                 return 0;
253         }
254
255         /* Modify signal */
256         if (set_h245_addr(pskb, data, dataoff, taddr,
257                           &ct->tuplehash[!dir].tuple.dst.u3,
258                           htons((port & htons(1)) ? nated_port + 1 :
259                                                     nated_port)) == 0) {
260                 /* Save ports */
261                 info->rtp_port[i][dir] = rtp_port;
262                 info->rtp_port[i][!dir] = htons(nated_port);
263         } else {
264                 nf_conntrack_unexpect_related(rtp_exp);
265                 nf_conntrack_unexpect_related(rtcp_exp);
266                 return -1;
267         }
268
269         /* Success */
270         DEBUGP("nf_nat_h323: expect RTP %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
271                NIPQUAD(rtp_exp->tuple.src.ip),
272                ntohs(rtp_exp->tuple.src.u.udp.port),
273                NIPQUAD(rtp_exp->tuple.dst.ip),
274                ntohs(rtp_exp->tuple.dst.u.udp.port));
275         DEBUGP("nf_nat_h323: expect RTCP %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
276                NIPQUAD(rtcp_exp->tuple.src.ip),
277                ntohs(rtcp_exp->tuple.src.u.udp.port),
278                NIPQUAD(rtcp_exp->tuple.dst.ip),
279                ntohs(rtcp_exp->tuple.dst.u.udp.port));
280
281         return 0;
282 }
283
284 /****************************************************************************/
285 static int nat_t120(struct sk_buff **pskb, struct nf_conn *ct,
286                     enum ip_conntrack_info ctinfo,
287                     unsigned char **data, int dataoff,
288                     H245_TransportAddress *taddr, __be16 port,
289                     struct nf_conntrack_expect *exp)
290 {
291         int dir = CTINFO2DIR(ctinfo);
292         u_int16_t nated_port = ntohs(port);
293
294         /* Set expectations for NAT */
295         exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
296         exp->expectfn = nf_nat_follow_master;
297         exp->dir = !dir;
298
299         /* Try to get same port: if not, try to change it. */
300         for (; nated_port != 0; nated_port++) {
301                 exp->tuple.dst.u.tcp.port = htons(nated_port);
302                 if (nf_conntrack_expect_related(exp) == 0)
303                         break;
304         }
305
306         if (nated_port == 0) {  /* No port available */
307                 if (net_ratelimit())
308                         printk("nf_nat_h323: out of TCP ports\n");
309                 return 0;
310         }
311
312         /* Modify signal */
313         if (set_h245_addr(pskb, data, dataoff, taddr,
314                           &ct->tuplehash[!dir].tuple.dst.u3,
315                           htons(nated_port)) < 0) {
316                 nf_conntrack_unexpect_related(exp);
317                 return -1;
318         }
319
320         DEBUGP("nf_nat_h323: expect T.120 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
321                NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port),
322                NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port));
323
324         return 0;
325 }
326
327 /****************************************************************************/
328 static int nat_h245(struct sk_buff **pskb, struct nf_conn *ct,
329                     enum ip_conntrack_info ctinfo,
330                     unsigned char **data, int dataoff,
331                     TransportAddress *taddr, __be16 port,
332                     struct nf_conntrack_expect *exp)
333 {
334         struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info;
335         int dir = CTINFO2DIR(ctinfo);
336         u_int16_t nated_port = ntohs(port);
337
338         /* Set expectations for NAT */
339         exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
340         exp->expectfn = nf_nat_follow_master;
341         exp->dir = !dir;
342
343         /* Check existing expects */
344         if (info->sig_port[dir] == port)
345                 nated_port = ntohs(info->sig_port[!dir]);
346
347         /* Try to get same port: if not, try to change it. */
348         for (; nated_port != 0; nated_port++) {
349                 exp->tuple.dst.u.tcp.port = htons(nated_port);
350                 if (nf_conntrack_expect_related(exp) == 0)
351                         break;
352         }
353
354         if (nated_port == 0) {  /* No port available */
355                 if (net_ratelimit())
356                         printk("nf_nat_q931: out of TCP ports\n");
357                 return 0;
358         }
359
360         /* Modify signal */
361         if (set_h225_addr(pskb, data, dataoff, taddr,
362                           &ct->tuplehash[!dir].tuple.dst.u3,
363                           htons(nated_port)) == 0) {
364                 /* Save ports */
365                 info->sig_port[dir] = port;
366                 info->sig_port[!dir] = htons(nated_port);
367         } else {
368                 nf_conntrack_unexpect_related(exp);
369                 return -1;
370         }
371
372         DEBUGP("nf_nat_q931: expect H.245 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
373                NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port),
374                NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port));
375
376         return 0;
377 }
378
379 /****************************************************************************
380  * This conntrack expect function replaces nf_conntrack_q931_expect()
381  * which was set by nf_conntrack_h323.c.
382  ****************************************************************************/
383 static void ip_nat_q931_expect(struct nf_conn *new,
384                                struct nf_conntrack_expect *this)
385 {
386         struct ip_nat_range range;
387
388         if (this->tuple.src.u3.ip != 0) {       /* Only accept calls from GK */
389                 nf_nat_follow_master(new, this);
390                 return;
391         }
392
393         /* This must be a fresh one. */
394         BUG_ON(new->status & IPS_NAT_DONE_MASK);
395
396         /* Change src to where master sends to */
397         range.flags = IP_NAT_RANGE_MAP_IPS;
398         range.min_ip = range.max_ip = new->tuplehash[!this->dir].tuple.src.u3.ip;
399
400         /* hook doesn't matter, but it has to do source manip */
401         nf_nat_setup_info(new, &range, NF_IP_POST_ROUTING);
402
403         /* For DST manip, map port here to where it's expected. */
404         range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED);
405         range.min = range.max = this->saved_proto;
406         range.min_ip = range.max_ip =
407             new->master->tuplehash[!this->dir].tuple.src.u3.ip;
408
409         /* hook doesn't matter, but it has to do destination manip */
410         nf_nat_setup_info(new, &range, NF_IP_PRE_ROUTING);
411 }
412
413 /****************************************************************************/
414 static int nat_q931(struct sk_buff **pskb, struct nf_conn *ct,
415                     enum ip_conntrack_info ctinfo,
416                     unsigned char **data, TransportAddress *taddr, int idx,
417                     __be16 port, struct nf_conntrack_expect *exp)
418 {
419         struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info;
420         int dir = CTINFO2DIR(ctinfo);
421         u_int16_t nated_port = ntohs(port);
422         union nf_conntrack_address addr;
423
424         /* Set expectations for NAT */
425         exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
426         exp->expectfn = ip_nat_q931_expect;
427         exp->dir = !dir;
428
429         /* Check existing expects */
430         if (info->sig_port[dir] == port)
431                 nated_port = ntohs(info->sig_port[!dir]);
432
433         /* Try to get same port: if not, try to change it. */
434         for (; nated_port != 0; nated_port++) {
435                 exp->tuple.dst.u.tcp.port = htons(nated_port);
436                 if (nf_conntrack_expect_related(exp) == 0)
437                         break;
438         }
439
440         if (nated_port == 0) {  /* No port available */
441                 if (net_ratelimit())
442                         printk("nf_nat_ras: out of TCP ports\n");
443                 return 0;
444         }
445
446         /* Modify signal */
447         if (set_h225_addr(pskb, data, 0, &taddr[idx],
448                           &ct->tuplehash[!dir].tuple.dst.u3,
449                           htons(nated_port)) == 0) {
450                 /* Save ports */
451                 info->sig_port[dir] = port;
452                 info->sig_port[!dir] = htons(nated_port);
453
454                 /* Fix for Gnomemeeting */
455                 if (idx > 0 &&
456                     get_h225_addr(ct, *data, &taddr[0], &addr, &port) &&
457                     (ntohl(addr.ip) & 0xff000000) == 0x7f000000) {
458                         set_h225_addr_hook(pskb, data, 0, &taddr[0],
459                                            &ct->tuplehash[!dir].tuple.dst.u3,
460                                            info->sig_port[!dir]);
461                 }
462         } else {
463                 nf_conntrack_unexpect_related(exp);
464                 return -1;
465         }
466
467         /* Success */
468         DEBUGP("nf_nat_ras: expect Q.931 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
469                NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port),
470                NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port));
471
472         return 0;
473 }
474
475 /****************************************************************************/
476 static void ip_nat_callforwarding_expect(struct nf_conn *new,
477                                          struct nf_conntrack_expect *this)
478 {
479         struct nf_nat_range range;
480
481         /* This must be a fresh one. */
482         BUG_ON(new->status & IPS_NAT_DONE_MASK);
483
484         /* Change src to where master sends to */
485         range.flags = IP_NAT_RANGE_MAP_IPS;
486         range.min_ip = range.max_ip = new->tuplehash[!this->dir].tuple.src.u3.ip;
487
488         /* hook doesn't matter, but it has to do source manip */
489         nf_nat_setup_info(new, &range, NF_IP_POST_ROUTING);
490
491         /* For DST manip, map port here to where it's expected. */
492         range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED);
493         range.min = range.max = this->saved_proto;
494         range.min_ip = range.max_ip = this->saved_ip;
495
496         /* hook doesn't matter, but it has to do destination manip */
497         nf_nat_setup_info(new, &range, NF_IP_PRE_ROUTING);
498 }
499
500 /****************************************************************************/
501 static int nat_callforwarding(struct sk_buff **pskb, struct nf_conn *ct,
502                               enum ip_conntrack_info ctinfo,
503                               unsigned char **data, int dataoff,
504                               TransportAddress *taddr, __be16 port,
505                               struct nf_conntrack_expect *exp)
506 {
507         int dir = CTINFO2DIR(ctinfo);
508         u_int16_t nated_port;
509
510         /* Set expectations for NAT */
511         exp->saved_ip = exp->tuple.dst.u3.ip;
512         exp->tuple.dst.u3.ip = ct->tuplehash[!dir].tuple.dst.u3.ip;
513         exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
514         exp->expectfn = ip_nat_callforwarding_expect;
515         exp->dir = !dir;
516
517         /* Try to get same port: if not, try to change it. */
518         for (nated_port = ntohs(port); nated_port != 0; nated_port++) {
519                 exp->tuple.dst.u.tcp.port = htons(nated_port);
520                 if (nf_conntrack_expect_related(exp) == 0)
521                         break;
522         }
523
524         if (nated_port == 0) {  /* No port available */
525                 if (net_ratelimit())
526                         printk("nf_nat_q931: out of TCP ports\n");
527                 return 0;
528         }
529
530         /* Modify signal */
531         if (!set_h225_addr(pskb, data, dataoff, taddr,
532                            &ct->tuplehash[!dir].tuple.dst.u3,
533                            htons(nated_port)) == 0) {
534                 nf_conntrack_unexpect_related(exp);
535                 return -1;
536         }
537
538         /* Success */
539         DEBUGP("nf_nat_q931: expect Call Forwarding "
540                "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
541                NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port),
542                NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port));
543
544         return 0;
545 }
546
547 /****************************************************************************/
548 static int __init init(void)
549 {
550         BUG_ON(rcu_dereference(set_h245_addr_hook) != NULL);
551         BUG_ON(rcu_dereference(set_h225_addr_hook) != NULL);
552         BUG_ON(rcu_dereference(set_sig_addr_hook) != NULL);
553         BUG_ON(rcu_dereference(set_ras_addr_hook) != NULL);
554         BUG_ON(rcu_dereference(nat_rtp_rtcp_hook) != NULL);
555         BUG_ON(rcu_dereference(nat_t120_hook) != NULL);
556         BUG_ON(rcu_dereference(nat_h245_hook) != NULL);
557         BUG_ON(rcu_dereference(nat_callforwarding_hook) != NULL);
558         BUG_ON(rcu_dereference(nat_q931_hook) != NULL);
559
560         rcu_assign_pointer(set_h245_addr_hook, set_h245_addr);
561         rcu_assign_pointer(set_h225_addr_hook, set_h225_addr);
562         rcu_assign_pointer(set_sig_addr_hook, set_sig_addr);
563         rcu_assign_pointer(set_ras_addr_hook, set_ras_addr);
564         rcu_assign_pointer(nat_rtp_rtcp_hook, nat_rtp_rtcp);
565         rcu_assign_pointer(nat_t120_hook, nat_t120);
566         rcu_assign_pointer(nat_h245_hook, nat_h245);
567         rcu_assign_pointer(nat_callforwarding_hook, nat_callforwarding);
568         rcu_assign_pointer(nat_q931_hook, nat_q931);
569
570         DEBUGP("nf_nat_h323: init success\n");
571         return 0;
572 }
573
574 /****************************************************************************/
575 static void __exit fini(void)
576 {
577         rcu_assign_pointer(set_h245_addr_hook, NULL);
578         rcu_assign_pointer(set_h225_addr_hook, NULL);
579         rcu_assign_pointer(set_sig_addr_hook, NULL);
580         rcu_assign_pointer(set_ras_addr_hook, NULL);
581         rcu_assign_pointer(nat_rtp_rtcp_hook, NULL);
582         rcu_assign_pointer(nat_t120_hook, NULL);
583         rcu_assign_pointer(nat_h245_hook, NULL);
584         rcu_assign_pointer(nat_callforwarding_hook, NULL);
585         rcu_assign_pointer(nat_q931_hook, NULL);
586         synchronize_rcu();
587 }
588
589 /****************************************************************************/
590 module_init(init);
591 module_exit(fini);
592
593 MODULE_AUTHOR("Jing Min Zhao <zhaojingmin@users.sourceforge.net>");
594 MODULE_DESCRIPTION("H.323 NAT helper");
595 MODULE_LICENSE("GPL");
596 MODULE_ALIAS("ip_nat_h323");