# BRCM_VERSION=3
[bcm963xx.git] / kernel / linux / net / ipv4 / netfilter / ip_conntrack_rtsp.c
1 /*
2  * RTSP extension for IP connection tracking
3  * (C) 2003 by Tom Marshall <tmarshall@real.com>
4  * based on ip_conntrack_irc.c
5  *
6  *      This program is free software; you can redistribute it and/or
7  *      modify it under the terms of the GNU General Public License
8  *      as published by the Free Software Foundation; either version
9  *      2 of the License, or (at your option) any later version.
10  *
11  * Module load syntax:
12  *   insmod ip_conntrack_rtsp.o ports=port1,port2,...port<MAX_PORTS>
13  *                              max_outstanding=n setup_timeout=secs
14  *
15  * If no ports are specified, the default will be port 554.
16  *
17  * With max_outstanding you can define the maximum number of not yet
18  * answered SETUP requests per RTSP session (default 8).
19  * With setup_timeout you can specify how long the system waits for
20  * an expected data channel (default 300 seconds).
21  */
22
23 #include <linux/config.h>
24 #include <linux/module.h>
25 #include <linux/netfilter.h>
26 #include <linux/ip.h>
27 #include <linux/udp.h>
28 #include <net/checksum.h>
29 #include <net/tcp.h>
30
31 #include <linux/netfilter_ipv4/lockhelp.h>
32 #include <linux/netfilter_ipv4/ip_nat_rtsp.h>
33 #include <linux/netfilter_ipv4/ip_conntrack_helper.h>
34 #include <linux/netfilter_ipv4/ip_conntrack_rtsp.h>
35
36 #include <linux/ctype.h>
37 #define NF_NEED_STRNCASECMP
38 #define NF_NEED_STRTOU16
39 #define NF_NEED_STRTOU32
40 #define NF_NEED_NEXTLINE
41 #include <linux/netfilter_helpers.h>
42 #define NF_NEED_MIME_NEXTLINE
43 #include <linux/netfilter_mime.h>
44
45 #define MAX_SIMUL_SETUP 8 /* XXX: use max_outstanding */
46
47 /*
48  * To enable debugging, replace the line below with #define IP_NF_RTSP_DEBUG 1
49  */
50 #undef IP_NF_RTSP_DEBUG
51 #define INFOP(args...) printk(KERN_INFO args)
52 #ifdef IP_NF_RTSP_DEBUG
53 #define DEBUGP(args...) printk(KERN_DEBUG "%s:%s ", __FILE__, __FUNCTION__); \
54                         printk(args)
55 #else
56 #define DEBUGP(args...)
57 #endif
58
59 #define MAX_PORTS 8
60 static int ports[MAX_PORTS];
61 static int num_ports = 0;
62 static int max_outstanding = 8;
63 static unsigned int setup_timeout = 300;
64
65 /* This is slow, but it's simple. --RR */
66 static char rtsp_buffer[65536];
67
68 MODULE_AUTHOR("Tom Marshall <tmarshall@real.com>");
69 MODULE_DESCRIPTION("RTSP connection tracking module");
70 MODULE_LICENSE("GPL");
71 #ifdef MODULE_PARM
72 MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");
73 MODULE_PARM_DESC(ports, "port numbers of RTSP servers");
74 MODULE_PARM(max_outstanding, "i");
75 MODULE_PARM_DESC(max_outstanding, "max number of outstanding SETUP requests per RTSP session");
76 MODULE_PARM(setup_timeout, "i");
77 MODULE_PARM_DESC(setup_timeout, "timeout on for unestablished data channels");
78 #endif
79
80 DECLARE_LOCK(ip_rtsp_lock);
81 struct module* ip_conntrack_rtsp = THIS_MODULE;
82
83 /*
84  * Max mappings we will allow for one RTSP connection (for RTP, the number
85  * of allocated ports is twice this value).  Note that SMIL burns a lot of
86  * ports so keep this reasonably high.  If this is too low, you will see a
87  * lot of "no free client map entries" messages.
88  */
89 #define MAX_PORT_MAPS 16
90 static u_int16_t g_tr_port = 10000;
91
92 /*** default port list was here in the masq code: 554, 3030, 4040 ***/
93
94 #define SKIP_WSPACE(ptr,len,off) while(off < len && isspace(*(ptr+off))) { off++; }
95 /*
96  * Structure to hold the mappings from client to NAT vice versa. If we
97  * mangle UDP ports in the outgoing SETUP message, we must properly
98  * mangle them in the return direction so that the client will
99  * process the packets appropriately.
100  */
101 struct _rtsp_data_ports {
102     u_int32_t   client_ip;
103     u_int16_t   client_tcp_port;
104     u_int16_t   client_udp_lo;
105     u_int16_t   client_udp_hi;
106     portblock_t pbtype;
107     u_int16_t   nat_udp_lo;
108     u_int16_t   nat_udp_hi;
109     int         in_use;
110 } rtsp_data_ports[MAX_PORT_MAPS];
111
112 /*
113  * Maps client ports that are overlapping with other client UDP transport to
114  * new NAT ports that will be tracked and converted back to client assigned
115  * UDP ports.
116  * Return (N/A)
117  */
118 static int
119 rtsp_client_to_nat_pmap(struct ip_ct_rtsp_expect *prtspexp, const struct iphdr *iph,
120                         struct ip_conntrack *ct)
121 {
122     int i  = 0;
123     int rc = 0;
124     struct tcphdr *tcph   = (void *)iph + iph->ihl * 4;
125
126     DEBUGP("IP %u.%u.%u.%u->%u.%u.%u.%u PORTS (%hu-%hu)\n", NIPQUAD(iph->saddr),
127            NIPQUAD(iph->daddr), tcph->source, tcph->dest);
128
129     for (i = 0; i < MAX_PORT_MAPS; i++) {
130         if (rtsp_data_ports[i].in_use) {
131             DEBUGP("Index %d in_use flag %d IP %u.%u.%u.%u CLIENT %hu-%hu NAT %hu-%hu\n", i,
132                    rtsp_data_ports[i].in_use, NIPQUAD(rtsp_data_ports[i].client_ip),
133                    rtsp_data_ports[i].client_udp_lo, rtsp_data_ports[i].client_udp_hi,
134                    rtsp_data_ports[i].nat_udp_lo, rtsp_data_ports[i].nat_udp_hi);
135             continue;
136         }
137             rtsp_data_ports[i].client_ip       = ntohl(iph->saddr);
138             rtsp_data_ports[i].client_tcp_port = ntohs(tcph->source);
139             rtsp_data_ports[i].client_udp_lo   = ntohs(prtspexp->loport);
140             rtsp_data_ports[i].client_udp_hi   = ntohs(prtspexp->hiport);
141             rtsp_data_ports[i].pbtype          = prtspexp->pbtype;
142             rtsp_data_ports[i].in_use          = 1;
143             DEBUGP("Mapped at index %d ORIGINAL PORTS %hu-%hu\n", i,
144                    ntohs(prtspexp->loport), ntohs(prtspexp->hiport));
145             prtspexp->loport  = rtsp_data_ports[i].nat_udp_lo = g_tr_port++;
146             prtspexp->hiport  = rtsp_data_ports[i].nat_udp_hi = g_tr_port++;
147             DEBUGP("NEW PORTS %hu-%hu\n", ntohs(prtspexp->loport), ntohs(prtspexp->hiport));
148             return rc = 1;
149     }
150     return rc;
151 }
152
153 /*
154  * Performs NAT to client port mapping. Incoming UDP ports are looked up and
155  * appropriate client ports are extracted from the table and returned.
156  * Return client_udp_port or 0 when no matches found.
157  */
158 static u_int16_t
159 rtsp_nat_to_client_pmap(u_int16_t nat_port)
160 {
161     int           i       = 0;
162     u_int16_t     tr_port = 0;
163
164     for (i = 0; i < MAX_PORT_MAPS; i++) {
165         if (!rtsp_data_ports[i].in_use) {
166             continue;
167         }
168         /*
169          * Check if the UDP ports match any of our NAT ports and return
170          * the client UDP ports.
171          */
172         DEBUGP("Searching at index %d NAT_PORT %hu CLIENT PORTS (%hu-%hu)\n", i,
173                ntohs(nat_port), rtsp_data_ports[i].client_udp_lo,
174                rtsp_data_ports[i].client_udp_hi);
175         if (ntohs(nat_port) == rtsp_data_ports[i].nat_udp_lo) {
176             tr_port = rtsp_data_ports[i].client_udp_lo;
177             DEBUGP("Found at index %d NAT_PORT %hu CLIENT PORTS (%hu-%hu) tr_port %hu\n", i,
178                    nat_port, rtsp_data_ports[i].client_udp_lo,
179                    rtsp_data_ports[i].client_udp_hi, tr_port);
180         } else if (ntohs(nat_port) == rtsp_data_ports[i].nat_udp_hi) {
181             tr_port = rtsp_data_ports[i].client_udp_hi;
182             DEBUGP("Found at index %d NAT_PORT %hu CLIENT PORTS %hu-%hu tr_port %hu\n", i,
183                    nat_port, rtsp_data_ports[i].client_udp_lo,
184                    rtsp_data_ports[i].client_udp_hi, tr_port);
185             return tr_port;
186         }
187     }
188     return tr_port;
189 }
190
191 static void
192 ip_conntrack_rtsp_proc_teardown(struct iphdr *iph)
193 {
194     int i    = 0;
195     struct tcphdr *tcph = (void *)iph + iph->ihl * 4;
196
197     for (i = 0; i < MAX_PORT_MAPS; i++)
198     {
199         if (!rtsp_data_ports[i].in_use)
200         {
201             continue;
202         }
203         DEBUGP("Searching client info IP %u.%u.%u.%u->%hu PORTS (%hu-%hu)\n",
204                 NIPQUAD(iph->saddr), tcph->source, rtsp_data_ports[i].client_udp_lo,
205                 rtsp_data_ports[i].client_udp_hi);
206         if ((rtsp_data_ports[i].client_ip == iph->saddr) &&
207             (rtsp_data_ports[i].client_tcp_port == tcph->source))
208         {
209             DEBUGP("Found client info SRC IP %u.%u.%u.%u TCP PORT %hu UDP PORTS (%hu-%hu)\n",
210                     NIPQUAD(iph->saddr), tcph->source, rtsp_data_ports[i].client_udp_lo,
211                     rtsp_data_ports[i].client_udp_hi);
212             rtsp_data_ports[i].in_use = 0;
213             break;
214         }
215     }
216 }
217
218 static void *
219 find_char(void *str, int ch, size_t len)
220 {
221     unsigned char *pStr = NULL;
222     if (len != 0) {
223         pStr = str;
224     }
225     do {
226         if (*pStr++ == ch) {
227             return ((void *)(pStr - 1));
228         }
229     } while (--len != 0);
230     return (NULL);
231 }
232
233 /*
234  * Parse an RTSP packet.
235  *
236  * Returns zero if parsing failed.
237  *
238  * Parameters:
239  *  IN      ptcp        tcp data pointer
240  *  IN      tcplen      tcp data len
241  *  IN/OUT  ptcpoff     points to current tcp offset
242  *  OUT     phdrsoff    set to offset of rtsp headers
243  *  OUT     phdrslen    set to length of rtsp headers
244  *  OUT     pcseqoff    set to offset of CSeq header
245  *  OUT     pcseqlen    set to length of CSeq header
246  */
247 static int
248 rtsp_parse_message(char* ptcp, uint tcplen, uint* ptcpoff,
249                    uint* phdrsoff, uint* phdrslen,
250                    uint* pcseqoff, uint* pcseqlen)
251 {
252     uint    entitylen = 0;
253     uint    lineoff;
254     uint    linelen;
255
256     if (!nf_nextline(ptcp, tcplen, ptcpoff, &lineoff, &linelen))
257     {
258         return 0;
259     }
260
261     *phdrsoff = *ptcpoff;
262     while (nf_mime_nextline(ptcp, tcplen, ptcpoff, &lineoff, &linelen))
263     {
264         if (linelen == 0)
265         {
266             if (entitylen > 0)
267             {
268                 *ptcpoff += min(entitylen, tcplen - *ptcpoff);
269             }
270             break;
271         }
272         if (lineoff+linelen > tcplen)
273         {
274             INFOP("!! overrun !!\n");
275             break;
276         }
277
278         if (nf_strncasecmp(ptcp+lineoff, "CSeq:", 5) == 0)
279         {
280             *pcseqoff = lineoff;
281             *pcseqlen = linelen;
282         }
283         if (nf_strncasecmp(ptcp+lineoff, "Content-Length:", 15) == 0)
284         {
285             uint off = lineoff+15;
286             SKIP_WSPACE(ptcp+lineoff, linelen, off);
287             nf_strtou32(ptcp+off, &entitylen);
288         }
289     }
290     *phdrslen = (*ptcpoff) - (*phdrsoff);
291
292     return 1;
293 }
294
295 /*
296  * Find lo/hi client ports (if any) in transport header
297  * In:
298  *   ptcp, tcplen = packet
299  *   tranoff, tranlen = buffer to search
300  *
301  * Out:
302  *   pport_lo, pport_hi = lo/hi ports (host endian)
303  *
304  * Returns nonzero if any client ports found
305  *
306  * Note: it is valid (and expected) for the client to request multiple
307  * transports, so we need to parse the entire line.
308  */
309 static int
310 rtsp_parse_transport(char* ptran, uint tranlen,
311                      struct ip_ct_rtsp_expect* prtspexp)
312 {
313     int     rc = 0;
314     uint    off = 0;
315
316     if (tranlen < 10 || !iseol(ptran[tranlen-1]) ||
317         nf_strncasecmp(ptran, "Transport:", 10) != 0)
318     {
319         INFOP("sanity check failed\n");
320         return 0;
321     }
322     DEBUGP("tran='%.*s'\n", (int)tranlen, ptran);
323     off += 10;
324     SKIP_WSPACE(ptran, tranlen, off);
325
326     /* Transport: tran;field;field=val,tran;field;field=val,... */
327     while (off < tranlen)
328     {
329         const char* pparamend;
330         uint        nextparamoff;
331
332         pparamend = memchr(ptran+off, ',', tranlen-off);
333         pparamend = (pparamend == NULL) ? ptran+tranlen : pparamend+1;
334         nextparamoff = pparamend-ptran;
335
336         while (off < nextparamoff)
337         {
338             const char* pfieldend;
339             uint        nextfieldoff;
340
341             pfieldend = find_char(ptran+off, ';', nextparamoff-off);
342             nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1;
343
344             if (strncmp(ptran+off, "client_port=", 12) == 0)
345             {
346                 u_int16_t   port;
347                 uint        numlen;
348
349                 off += 12;
350                 numlen = nf_strtou16(ptran+off, &port);
351                 off += numlen;
352                 if (prtspexp->loport != 0 && prtspexp->loport != port)
353                 {
354                     DEBUGP("multiple ports found, port %hu ignored\n", port);
355                 }
356                 else
357                 {
358                     prtspexp->loport = prtspexp->hiport = port;
359                     if (ptran[off] == '-')
360                     {
361                         off++;
362                         numlen = nf_strtou16(ptran+off, &port);
363                         off += numlen;
364                         prtspexp->pbtype = pb_range;
365                         prtspexp->hiport = port;
366
367                         // If we have a range, assume rtp:
368                         // loport must be even, hiport must be loport+1
369                         if ((prtspexp->loport & 0x0001) != 0 ||
370                             prtspexp->hiport != prtspexp->loport+1)
371                         {
372                             DEBUGP("incorrect range: %hu-%hu, correcting\n",
373                                    prtspexp->loport, prtspexp->hiport);
374                             prtspexp->loport &= 0xfffe;
375                             prtspexp->hiport = prtspexp->loport+1;
376                         }
377                     }
378                     else if (ptran[off] == '/')
379                     {
380                         off++;
381                         numlen = nf_strtou16(ptran+off, &port);
382                         off += numlen;
383                         prtspexp->pbtype = pb_discon;
384                         prtspexp->hiport = port;
385                     }
386                     rc = 1;
387                 }
388             }
389
390             /*
391              * Note we don't look for the destination parameter here.
392              * If we are using NAT, the NAT module will handle it.  If not,
393              * and the client is sending packets elsewhere, the expectation
394              * will quietly time out.
395              */
396
397             off = nextfieldoff;
398         }
399
400         off = nextparamoff;
401     }
402
403     return rc;
404 }
405
406 static int
407 rtp_expect(struct ip_conntrack *ct)
408 {
409     u_int16_t nat_port = ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u.udp.port;
410     DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
411     DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
412     ct->nat.rtsp_info.orig_port = rtsp_nat_to_client_pmap(nat_port);
413     DEBUGP("UDP client port %hu\n", ct->nat.rtsp_info.orig_port);
414
415     return NF_ACCEPT;
416 }
417
418 /*** conntrack functions ***/
419
420 /* outbound packet: client->server */
421 static int
422 help_out(struct iphdr* iph, char* pdata, size_t datalen,
423                 struct ip_conntrack* ct, enum ip_conntrack_info ctinfo)
424 {
425     int dir = CTINFO2DIR(ctinfo);   /* = IP_CT_DIR_ORIGINAL */
426     uint    dataoff = 0;
427     struct tcphdr *tcph = (void *)iph + iph->ihl * 4;
428
429     struct ip_conntrack_expect exp;
430
431     while (dataoff < datalen)
432     {
433         uint    cmdoff = dataoff;
434         uint    hdrsoff = 0;
435         uint    hdrslen = 0;
436         uint    cseqoff = 0;
437         uint    cseqlen = 0;
438         uint    lineoff = 0;
439         uint    linelen = 0;
440         uint    off;
441         int     rc;
442         uint    port = 0;
443         int     i    = 0;
444         struct  ip_conntrack_expect *new_exp = NULL;
445
446         if (!rtsp_parse_message(pdata, datalen, &dataoff,
447                                 &hdrsoff, &hdrslen,
448                                 &cseqoff, &cseqlen))
449         {
450             break;      /* not a valid message */
451         }
452
453         if (strncmp(pdata+cmdoff, "TEARDOWN ", 6) == 0)
454         {
455             ip_conntrack_rtsp_proc_teardown(iph);   /* TEARDOWN message */
456             continue;
457         }
458
459         if (strncmp(pdata+cmdoff, "SETUP ", 6) != 0)
460         {
461             continue;   /* not a SETUP message */
462         }
463         DEBUGP("found a setup message\n");
464
465         memset(&exp, 0, sizeof(exp));
466
467         off = 0;
468         
469         while (nf_mime_nextline(pdata+hdrsoff, hdrslen, &off,
470                                 &lineoff, &linelen))
471         {
472             if (linelen == 0)
473             {
474                 break;
475             }
476             if (off > hdrsoff+hdrslen)
477             {
478                 INFOP("!! overrun !!");
479                 break;
480             }
481
482             if (nf_strncasecmp(pdata+hdrsoff+lineoff, "Transport:", 10) == 0)
483             {
484                 rtsp_parse_transport(pdata+hdrsoff+lineoff, linelen,
485                                      &exp.help.exp_rtsp_info);
486             }
487         }
488
489         if (exp.help.exp_rtsp_info.loport == 0)
490         {
491             DEBUGP("no udp transports found\n");
492             continue;   /* no udp transports found */
493         }
494
495         DEBUGP("udp transport found, ports=(%d,%hu,%hu)\n",
496               (int)exp.help.exp_rtsp_info.pbtype,
497               exp.help.exp_rtsp_info.loport,
498               exp.help.exp_rtsp_info.hiport);
499
500         LOCK_BH(&ip_rtsp_lock);
501        /*
502          * Translate the original ports to the NAT ports and note them
503          * down to translate back in the return direction.
504          */
505         if (!rtsp_client_to_nat_pmap(&exp.help.exp_rtsp_info, iph, ct))
506         {
507             DEBUGP("Dropping the packet. No more space in the mapping table\n");
508             UNLOCK_BH(&ip_rtsp_lock);
509             return NF_DROP;
510         }
511         i = 0;
512         port = exp.help.exp_rtsp_info.loport;
513         while (i < 2) {
514             /*
515              * Allocate expectation for tracking this connection
516              */
517             new_exp = ip_conntrack_expect_alloc();
518             if (!new_exp) {
519                 INFOP("Failed to get a new expectation entry\n");
520                 UNLOCK_BH(&ip_rtsp_lock);
521                 return NF_DROP;
522             }
523             memcpy(new_exp, &exp, sizeof(struct ip_conntrack_expect));
524             new_exp->seq = ntohl(tcph->seq) + hdrsoff; /* mark all the headers */
525             new_exp->help.exp_rtsp_info.len = hdrslen;
526
527             DEBUGP("Adding UDP port %hu,%hu\n", htons(port), ntohs(port));
528
529             new_exp->tuple = ct->tuplehash[!dir].tuple;
530             new_exp->tuple.dst.u.udp.port = htons(port);
531             new_exp->tuple.dst.protonum = IPPROTO_UDP;
532             new_exp->mask.src.ip  = 0xffffffff;
533             new_exp->mask.dst.ip  = 0xffffffff;
534             //exp.mask.dst.u.udp.port  = (exp.help.exp_rtsp_info.pbtype == pb_range) ? 0xfffe : 0xffff;
535             new_exp->mask.dst.u.udp.port  = 0xffff;
536             new_exp->expectfn = rtp_expect;
537             new_exp->mask.dst.protonum  = 0xffff;
538
539             DEBUGP("expect_related %u.%u.%u.%u:%u-%u.%u.%u.%u:%u\n",
540                     NIPQUAD(new_exp->tuple.src.ip),
541                     ntohs(new_exp->tuple.src.u.tcp.port),
542                     NIPQUAD(new_exp->tuple.dst.ip),
543                     ntohs(new_exp->tuple.dst.u.tcp.port));
544
545             /* pass the request off to the nat helper */
546             rc = ip_conntrack_expect_related(new_exp, ct);
547             if (rc == 0)
548             {
549                 DEBUGP("ip_conntrack_expect_related succeeded\n");
550             }
551             else
552             {
553                 INFOP("ip_conntrack_expect_related failed\n");
554             }
555             port++;
556             i++;
557         }
558         UNLOCK_BH(&ip_rtsp_lock);
559     }
560
561     return NF_ACCEPT;
562 }
563
564 /* inbound packet: server->client */
565 static int
566 help_in(struct tcphdr* tcph, char* pdata, size_t datalen,
567                 struct ip_conntrack* ct, enum ip_conntrack_info ctinfo)
568 {
569     return NF_ACCEPT;
570 }
571
572 static int
573 help(struct sk_buff* skb,
574                 struct ip_conntrack* ct, enum ip_conntrack_info ctinfo)
575 {
576     uint dataoff;
577     struct iphdr *iph = skb->nh.iph;
578     struct tcphdr tcph;
579     char* data;
580     uint datalen;
581
582     /* Until there's been traffic both ways, don't look in packets. */
583     if (ctinfo != IP_CT_ESTABLISHED && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY)
584     {
585         DEBUGP("conntrackinfo = %u\n", ctinfo);
586         return NF_ACCEPT;
587     }
588
589     /* Not whole TCP header? */
590     if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &tcph, sizeof(tcph)) != 0)
591     {
592         return NF_ACCEPT;
593     }
594
595     /* No data? */
596     dataoff = skb->nh.iph->ihl*4 + tcph.doff*4;
597     if ( skb->nh.iph->ihl*4 + tcph.doff*4 >= skb->len)
598     {
599         return NF_ACCEPT;
600     }
601
602     LOCK_BH(&ip_rtsp_lock);
603     skb_copy_bits(skb, dataoff, rtsp_buffer, skb->len - dataoff);
604     data = rtsp_buffer;
605     datalen = skb->len - dataoff;
606     switch (CTINFO2DIR(ctinfo))
607     {
608     case IP_CT_DIR_ORIGINAL:
609         help_out(iph, data, datalen, ct, ctinfo);
610         break;
611     case IP_CT_DIR_REPLY:
612         help_in(&tcph, data, datalen, ct, ctinfo);
613         break;
614     default:
615         /* oops */
616         break;
617     }
618     UNLOCK_BH(&ip_rtsp_lock);
619
620     return NF_ACCEPT;
621 }
622
623 static struct ip_conntrack_helper rtsp_helpers[MAX_PORTS];
624 static char rtsp_names[MAX_PORTS][10];
625
626 static void
627 fini(void)
628 {
629     int i;
630     for (i = 0; i < num_ports; i++)
631     {
632         DEBUGP("unregistering port %d\n", ports[i]);
633         ip_conntrack_helper_unregister(&rtsp_helpers[i]);
634     }
635 }
636
637 static int __init
638 init(void)
639 {
640     int i, ret;
641     struct ip_conntrack_helper *hlpr;
642     char *tmpname;
643
644     printk("ip_conntrack_rtsp v" IP_NF_RTSP_VERSION " loading\n");
645
646     if (max_outstanding < 1)
647     {
648         printk("ip_conntrack_rtsp: max_outstanding must be a positive integer\n");
649         return -EBUSY;
650     }
651     if (setup_timeout < 0)
652     {
653         printk("ip_conntrack_rtsp: setup_timeout must be a positive integer\n");
654         return -EBUSY;
655     }
656
657     /* If no port given, default to standard rtsp port */
658     if (ports[0] == 0)
659     {
660         ports[0] = RTSP_PORT;
661     }
662
663     for (i = 0; i < MAX_PORT_MAPS; i++)
664     {
665         memset(&rtsp_data_ports[i], 0, sizeof(struct _rtsp_data_ports));
666         rtsp_data_ports[i].in_use     = 0;
667     }
668
669     for (i = 0; (i < MAX_PORTS) && ports[i]; i++)
670     {
671         hlpr = &rtsp_helpers[i];
672         memset(hlpr, 0, sizeof(struct ip_conntrack_helper));
673         hlpr->tuple.src.u.tcp.port = htons(ports[i]);
674         hlpr->tuple.dst.protonum = IPPROTO_TCP;
675         hlpr->mask.src.u.tcp.port = 0xFFFF;
676         hlpr->mask.dst.protonum = 0xFFFF;
677         hlpr->max_expected = max_outstanding;
678         hlpr->timeout = 0;
679         hlpr->flags = IP_CT_HELPER_F_REUSE_EXPECT;
680         hlpr->me = ip_conntrack_rtsp;
681         hlpr->help = help;
682
683         tmpname = &rtsp_names[i][0];
684         if (ports[i] == RTSP_PORT)
685         {
686             sprintf(tmpname, "rtsp");
687         }
688         else
689         {
690             sprintf(tmpname, "rtsp-%d", i);
691         }
692         hlpr->name = tmpname;
693
694         DEBUGP("port #%d: %d\n", i, ports[i]);
695
696         ret = ip_conntrack_helper_register(hlpr);
697
698         if (ret)
699         {
700             printk("ip_conntrack_rtsp: ERROR registering port %d\n", ports[i]);
701             fini();
702             return -EBUSY;
703         }
704         num_ports++;
705     }
706     return 0;
707 }
708
709 PROVIDES_CONNTRACK(rtsp);
710 EXPORT_SYMBOL(ip_rtsp_lock);
711
712 module_init(init);
713 module_exit(fini);