www.usr.com/support/gpl/USR9107_release.1.4.tar.gz
[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 = 7000;
91
92 #define PAUSE_TIMEOUT      (5 * HZ)
93 #define RTSP_PAUSE_TIMEOUT (6 * HZ)
94
95 /*** default port list was here in the masq code: 554, 3030, 4040 ***/
96
97 #define SKIP_WSPACE(ptr,len,off) while(off < len && isspace(*(ptr+off))) { off++; }
98 /*
99  * Structure to hold the mappings from client to NAT vice versa. If we
100  * mangle UDP ports in the outgoing SETUP message, we must properly
101  * mangle them in the return direction so that the client will
102  * process the packets appropriately.
103  */
104 struct _rtsp_data_ports {
105     u_int32_t           client_ip;
106     u_int16_t           client_tcp_port;
107     u_int16_t           client_udp_lo;
108     u_int16_t           client_udp_hi;
109     portblock_t         pbtype;
110     u_int16_t           nat_udp_lo;
111     u_int16_t           nat_udp_hi;
112     struct timer_list   pause_timeout;
113     struct ip_conntrack *ct_lo;
114     struct ip_conntrack *ct_hi;
115     int                 timeout_active;
116     int                 in_use;
117 } rtsp_data_ports[MAX_PORT_MAPS];
118
119 static u_int16_t rtsp_nat_to_client_pmap(u_int16_t nat_port);
120
121 static void
122 save_ct(struct ip_conntrack *ct)
123 {
124     int i    = 0;
125     struct ip_conntrack_tuple *tp = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
126
127     for (i = 0; i < MAX_PORT_MAPS; i++)
128     {
129         if (!rtsp_data_ports[i].in_use)
130         {
131             continue;
132         }
133         if (rtsp_data_ports[i].nat_udp_lo == ntohs((tp)->dst.u.all))
134         {
135             rtsp_data_ports[i].ct_lo = ct;
136             break;
137         }
138         else if (rtsp_data_ports[i].nat_udp_hi == ntohs((tp)->dst.u.all))
139         {
140             rtsp_data_ports[i].ct_hi = ct;
141             break;
142         }
143     }
144 }
145
146 static void
147 rtsp_pause_timeout(unsigned long data)
148 {
149     int    index = (int)data;
150     struct _rtsp_data_ports *rtsp_data = &rtsp_data_ports[index];
151     struct ip_conntrack *ct_lo = rtsp_data->ct_lo;
152
153     if (rtsp_data->in_use) {
154         rtsp_data->pause_timeout.expires = jiffies + PAUSE_TIMEOUT;
155         rtsp_data->pause_timeout.function = rtsp_pause_timeout;
156         rtsp_data->pause_timeout.data = data;
157         rtsp_data->timeout_active = 1;
158         ip_ct_refresh(ct_lo, RTSP_PAUSE_TIMEOUT);
159         add_timer(&rtsp_data->pause_timeout);
160     }
161 }
162
163 static void
164 ip_conntrack_rtsp_proc_play(struct ip_conntrack *ct, const struct iphdr *iph)
165 {
166     int i    = 0;
167     struct tcphdr *tcph = (void *)iph + iph->ihl * 4;
168
169     for (i = 0; i < MAX_PORT_MAPS; i++)
170     {
171         if (!rtsp_data_ports[i].in_use)
172         {
173             continue;
174         }
175         DEBUGP("Searching client info IP %u.%u.%u.%u->%hu PORTS (%hu-%hu)\n",
176                 NIPQUAD(iph->saddr), tcph->source, rtsp_data_ports[i].client_udp_lo,
177                 rtsp_data_ports[i].client_udp_hi);
178         if ((rtsp_data_ports[i].client_ip == iph->saddr) &&
179             (rtsp_data_ports[i].client_tcp_port == tcph->source))
180         {
181             DEBUGP("Found client info SRC IP %u.%u.%u.%u TCP PORT %hu UDP PORTS (%hu-%hu)\n",
182                     NIPQUAD(iph->saddr), tcph->source, rtsp_data_ports[i].client_udp_lo,
183                     rtsp_data_ports[i].client_udp_hi);
184             if (rtsp_data_ports[i].timeout_active)
185             {
186                 del_timer(&rtsp_data_ports[i].pause_timeout);
187                 rtsp_data_ports[i].timeout_active = 0;
188             }
189         }
190     }
191 }
192
193 static void
194 ip_conntrack_rtsp_proc_pause(struct ip_conntrack *ct, const struct iphdr *iph)
195 {
196     int i    = 0;
197     struct tcphdr *tcph = (void *)iph + iph->ihl * 4;
198     struct ip_conntrack_tuple *tp_lo;
199     struct ip_conntrack_tuple *tp_hi;
200     struct ip_conntrack *ct_lo;
201     struct ip_conntrack *ct_hi;
202
203     for (i = 0; i < MAX_PORT_MAPS; i++)
204     {
205         if (!rtsp_data_ports[i].in_use)
206         {
207             continue;
208         }
209         DEBUGP("Searching client info IP %u.%u.%u.%u->%hu 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         if ((rtsp_data_ports[i].client_ip == iph->saddr) &&
213             (rtsp_data_ports[i].client_tcp_port == tcph->source))
214         {
215             DEBUGP("Found client info SRC IP %u.%u.%u.%u TCP PORT %hu UDP PORTS (%hu-%hu)\n",
216                     NIPQUAD(iph->saddr), tcph->source, rtsp_data_ports[i].client_udp_lo,
217                     rtsp_data_ports[i].client_udp_hi);
218             if (rtsp_data_ports[i].timeout_active != 0 ||
219                 rtsp_data_ports[i].ct_lo == NULL)
220             {
221                 break;
222             }
223             rtsp_data_ports[i].pause_timeout.expires = jiffies + PAUSE_TIMEOUT;
224             rtsp_data_ports[i].pause_timeout.function = rtsp_pause_timeout;
225             rtsp_data_ports[i].pause_timeout.data = (unsigned long)i;
226             add_timer(&rtsp_data_ports[i].pause_timeout);
227             rtsp_data_ports[i].timeout_active = 1;
228             rtsp_data_ports[i].ct_lo = ct;
229             tp_lo = &ct_lo->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
230             tp_hi = &ct_hi->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
231             ip_ct_refresh(ct, RTSP_PAUSE_TIMEOUT);
232         }
233     }
234 }
235
236 static int
237 rtp_expect(struct ip_conntrack *ct)
238 {
239     u_int16_t nat_port = ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u.udp.port;
240     u_int16_t orig_port = 0;
241     DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
242     DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
243     orig_port = rtsp_nat_to_client_pmap(nat_port);
244     if (orig_port)
245     {
246         ct->nat.rtsp_info.orig_port = orig_port;
247     } else {
248         return NF_DROP;
249     }
250     DEBUGP("UDP client port %hu\n", ct->nat.rtsp_info.orig_port);
251     save_ct(ct);
252
253     return NF_ACCEPT;
254 }
255
256 /*
257  * Maps client ports that are overlapping with other client UDP transport to
258  * new NAT ports that will be tracked and converted back to client assigned
259  * UDP ports.
260  * Return (N/A)
261  */
262 static int
263 rtsp_client_to_nat_pmap(struct ip_ct_rtsp_expect *prtspexp, const struct iphdr *iph,
264                         struct ip_conntrack *ct)
265 {
266     int i  = 0;
267     int rc = 0;
268     struct tcphdr *tcph   = (void *)iph + iph->ihl * 4;
269
270     DEBUGP("IP %u.%u.%u.%u->%u.%u.%u.%u PORTS (%hu-%hu)\n", NIPQUAD(iph->saddr),
271            NIPQUAD(iph->daddr), tcph->source, tcph->dest);
272
273     for (i = 0; i < MAX_PORT_MAPS; i++) {
274         if (rtsp_data_ports[i].in_use) {
275             DEBUGP("Index %d in_use flag %d IP %u.%u.%u.%u CLIENT %hu-%hu NAT %hu-%hu\n", i,
276                    rtsp_data_ports[i].in_use, NIPQUAD(rtsp_data_ports[i].client_ip),
277                    rtsp_data_ports[i].client_udp_lo, rtsp_data_ports[i].client_udp_hi,
278                    rtsp_data_ports[i].nat_udp_lo, rtsp_data_ports[i].nat_udp_hi);
279             if (ntohl(iph->saddr) == rtsp_data_ports[i].client_ip &&
280                 ntohs(tcph->source) == rtsp_data_ports[i].client_tcp_port &&
281                 ntohs(prtspexp->loport) == rtsp_data_ports[i].client_udp_lo &&
282                 ntohs(prtspexp->hiport) == rtsp_data_ports[i].client_udp_hi)
283             {
284                 prtspexp->loport  = rtsp_data_ports[i].nat_udp_lo;
285                 prtspexp->hiport  = rtsp_data_ports[i].nat_udp_hi;
286                 return rc = 2;
287             }
288             continue;
289         }
290         rtsp_data_ports[i].client_ip       = ntohl(iph->saddr);
291         rtsp_data_ports[i].client_tcp_port = ntohs(tcph->source);
292         rtsp_data_ports[i].client_udp_lo   = ntohs(prtspexp->loport);
293         rtsp_data_ports[i].client_udp_hi   = ntohs(prtspexp->hiport);
294         rtsp_data_ports[i].pbtype          = prtspexp->pbtype;
295         rtsp_data_ports[i].in_use          = 1;
296         init_timer(&rtsp_data_ports[i].pause_timeout);
297         DEBUGP("Mapped at index %d ORIGINAL PORTS %hu-%hu\n", i,
298                ntohs(prtspexp->loport), ntohs(prtspexp->hiport));
299         prtspexp->loport  = rtsp_data_ports[i].nat_udp_lo = g_tr_port++;
300         prtspexp->hiport  = rtsp_data_ports[i].nat_udp_hi = g_tr_port++;
301         DEBUGP("NEW PORTS %hu-%hu\n", ntohs(prtspexp->loport), ntohs(prtspexp->hiport));
302         return rc = 1;
303     }
304     return rc;
305 }
306
307 /*
308  * Performs NAT to client port mapping. Incoming UDP ports are looked up and
309  * appropriate client ports are extracted from the table and returned.
310  * Return client_udp_port or 0 when no matches found.
311  */
312 static u_int16_t
313 rtsp_nat_to_client_pmap(u_int16_t nat_port)
314 {
315     int           i       = 0;
316     u_int16_t     tr_port = 0;
317
318     for (i = 0; i < MAX_PORT_MAPS; i++) {
319         if (!rtsp_data_ports[i].in_use) {
320             continue;
321         }
322         /*
323          * Check if the UDP ports match any of our NAT ports and return
324          * the client UDP ports.
325          */
326         DEBUGP("Searching at index %d NAT_PORT %hu CLIENT PORTS (%hu-%hu)\n", i,
327                ntohs(nat_port), rtsp_data_ports[i].client_udp_lo,
328                rtsp_data_ports[i].client_udp_hi);
329         if (ntohs(nat_port) == rtsp_data_ports[i].nat_udp_lo ||
330             ntohs(nat_port) == rtsp_data_ports[i].client_udp_lo) {
331             tr_port = rtsp_data_ports[i].client_udp_lo;
332             DEBUGP("Found at index %d NAT_PORT %hu CLIENT PORTS (%hu-%hu) tr_port %hu\n", i,
333                    nat_port, rtsp_data_ports[i].client_udp_lo,
334                    rtsp_data_ports[i].client_udp_hi, tr_port);
335         } else if (ntohs(nat_port) == rtsp_data_ports[i].nat_udp_hi ||
336                    ntohs(nat_port) == rtsp_data_ports[i].client_udp_hi) {
337             tr_port = rtsp_data_ports[i].client_udp_hi;
338             DEBUGP("Found at index %d NAT_PORT %hu CLIENT PORTS %hu-%hu tr_port %hu\n", i,
339                    nat_port, rtsp_data_ports[i].client_udp_lo,
340                    rtsp_data_ports[i].client_udp_hi, tr_port);
341             return tr_port;
342         }
343     }
344     return tr_port;
345 }
346
347 static void
348 ip_conntrack_rtsp_proc_teardown(struct iphdr *iph)
349 {
350     int i    = 0;
351     struct tcphdr *tcph = (void *)iph + iph->ihl * 4;
352
353     for (i = 0; i < MAX_PORT_MAPS; i++)
354     {
355         if (!rtsp_data_ports[i].in_use)
356         {
357             continue;
358         }
359         DEBUGP("Searching client info IP %u.%u.%u.%u->%hu PORTS (%hu-%hu)\n",
360                 NIPQUAD(iph->saddr), tcph->source, rtsp_data_ports[i].client_udp_lo,
361                 rtsp_data_ports[i].client_udp_hi);
362         if ((rtsp_data_ports[i].client_ip == iph->saddr) &&
363             (rtsp_data_ports[i].client_tcp_port == tcph->source))
364         {
365             DEBUGP("Found client info SRC IP %u.%u.%u.%u TCP PORT %hu UDP PORTS (%hu-%hu)\n",
366                     NIPQUAD(iph->saddr), tcph->source, rtsp_data_ports[i].client_udp_lo,
367                     rtsp_data_ports[i].client_udp_hi);
368             if (rtsp_data_ports[i].timeout_active)
369             {
370                 del_timer(&rtsp_data_ports[i].pause_timeout);
371                 rtsp_data_ports[i].timeout_active = 0;
372             }
373             memset(&rtsp_data_ports[i], 0, sizeof(struct _rtsp_data_ports));
374             rtsp_data_ports[i].in_use = 0;
375             //break;
376         }
377     }
378 }
379
380 static void *
381 find_char(void *str, int ch, size_t len)
382 {
383     unsigned char *pStr = NULL;
384     if (len != 0) {
385         pStr = str;
386     }
387     do {
388         if (*pStr++ == ch) {
389             return ((void *)(pStr - 1));
390         }
391     } while (--len != 0);
392     return (NULL);
393 }
394
395 /*
396  * Parse an RTSP packet.
397  *
398  * Returns zero if parsing failed.
399  *
400  * Parameters:
401  *  IN      ptcp        tcp data pointer
402  *  IN      tcplen      tcp data len
403  *  IN/OUT  ptcpoff     points to current tcp offset
404  *  OUT     phdrsoff    set to offset of rtsp headers
405  *  OUT     phdrslen    set to length of rtsp headers
406  *  OUT     pcseqoff    set to offset of CSeq header
407  *  OUT     pcseqlen    set to length of CSeq header
408  */
409 static int
410 rtsp_parse_message(char* ptcp, uint tcplen, uint* ptcpoff,
411                    uint* phdrsoff, uint* phdrslen,
412                    uint* pcseqoff, uint* pcseqlen)
413 {
414     uint    entitylen = 0;
415     uint    lineoff;
416     uint    linelen;
417
418     if (!nf_nextline(ptcp, tcplen, ptcpoff, &lineoff, &linelen))
419     {
420         return 0;
421     }
422
423     *phdrsoff = *ptcpoff;
424     while (nf_mime_nextline(ptcp, tcplen, ptcpoff, &lineoff, &linelen))
425     {
426         if (linelen == 0)
427         {
428             if (entitylen > 0)
429             {
430                 *ptcpoff += min(entitylen, tcplen - *ptcpoff);
431             }
432             break;
433         }
434         if (lineoff+linelen > tcplen)
435         {
436             INFOP("!! overrun !!\n");
437             break;
438         }
439
440         if (nf_strncasecmp(ptcp+lineoff, "CSeq:", 5) == 0)
441         {
442             *pcseqoff = lineoff;
443             *pcseqlen = linelen;
444         }
445         if (nf_strncasecmp(ptcp+lineoff, "Content-Length:", 15) == 0)
446         {
447             uint off = lineoff+15;
448             SKIP_WSPACE(ptcp+lineoff, linelen, off);
449             nf_strtou32(ptcp+off, &entitylen);
450         }
451     }
452     *phdrslen = (*ptcpoff) - (*phdrsoff);
453
454     return 1;
455 }
456
457 /*
458  * Find lo/hi client ports (if any) in transport header
459  * In:
460  *   ptcp, tcplen = packet
461  *   tranoff, tranlen = buffer to search
462  *
463  * Out:
464  *   pport_lo, pport_hi = lo/hi ports (host endian)
465  *
466  * Returns nonzero if any client ports found
467  *
468  * Note: it is valid (and expected) for the client to request multiple
469  * transports, so we need to parse the entire line.
470  */
471 static int
472 rtsp_parse_transport(char* ptran, uint tranlen,
473                      struct ip_ct_rtsp_expect* prtspexp)
474 {
475     int     rc = 0;
476     uint    off = 0;
477
478     if (tranlen < 10 || !iseol(ptran[tranlen-1]) ||
479         nf_strncasecmp(ptran, "Transport:", 10) != 0)
480     {
481         INFOP("sanity check failed\n");
482         return 0;
483     }
484     DEBUGP("tran='%.*s'\n", (int)tranlen, ptran);
485     off += 10;
486     SKIP_WSPACE(ptran, tranlen, off);
487
488     /* Transport: tran;field;field=val,tran;field;field=val,... */
489     while (off < tranlen)
490     {
491         const char* pparamend;
492         uint        nextparamoff;
493
494         pparamend = find_char(ptran+off, ',', tranlen-off);
495         pparamend = (pparamend == NULL) ? ptran+tranlen : pparamend+1;
496         nextparamoff = pparamend-ptran;
497
498         while (off < nextparamoff)
499         {
500             const char* pfieldend;
501             uint        nextfieldoff;
502
503             pfieldend = find_char(ptran+off, ';', nextparamoff-off);
504             nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1;
505
506             if (strncmp(ptran+off, "client_port=", 12) == 0)
507             {
508                 u_int16_t   port;
509                 uint        numlen;
510
511                 off += 12;
512                 numlen = nf_strtou16(ptran+off, &port);
513                 off += numlen;
514                 if (prtspexp->loport != 0 && prtspexp->loport != port)
515                 {
516                     DEBUGP("multiple ports found, port %hu ignored\n", port);
517                 }
518                 else
519                 {
520                     prtspexp->loport = prtspexp->hiport = port;
521                     DEBUGP("DASH or SLASH 0x%x\n", ptran[off]);
522                     if (ptran[off] == '-')
523                     {
524                         off++;
525                         numlen = nf_strtou16(ptran+off, &port);
526                         off += numlen;
527                         prtspexp->pbtype = pb_range;
528                         prtspexp->hiport = port;
529
530                         // If we have a range, assume rtp:
531                         // loport must be even, hiport must be loport+1
532                         if ((prtspexp->loport & 0x0001) != 0 ||
533                             prtspexp->hiport != prtspexp->loport+1)
534                         {
535                             DEBUGP("incorrect range: %hu-%hu, correcting\n",
536                                    prtspexp->loport, prtspexp->hiport);
537                             prtspexp->loport &= 0xfffe;
538                             prtspexp->hiport = prtspexp->loport+1;
539                         }
540                     }
541                     else if (ptran[off] == '/')
542                     {
543                         off++;
544                         numlen = nf_strtou16(ptran+off, &port);
545                         off += numlen;
546                         prtspexp->pbtype = pb_discon;
547                         prtspexp->hiport = port;
548                     }
549                     rc = 1;
550                 }
551             }
552
553             /*
554              * Note we don't look for the destination parameter here.
555              * If we are using NAT, the NAT module will handle it.  If not,
556              * and the client is sending packets elsewhere, the expectation
557              * will quietly time out.
558              */
559
560             off = nextfieldoff;
561         }
562
563         off = nextparamoff;
564     }
565
566     return rc;
567 }
568
569 /*** conntrack functions ***/
570
571 /* outbound packet: client->server */
572 static int
573 help_out(struct iphdr* iph, char* pdata, size_t datalen,
574                 struct ip_conntrack* ct, enum ip_conntrack_info ctinfo)
575 {
576     int dir = CTINFO2DIR(ctinfo);   /* = IP_CT_DIR_ORIGINAL */
577     uint    dataoff = 0;
578     struct tcphdr *tcph = (void *)iph + iph->ihl * 4;
579
580     struct ip_conntrack_expect exp;
581
582     while (dataoff < datalen)
583     {
584         uint    cmdoff = dataoff;
585         uint    hdrsoff = 0;
586         uint    hdrslen = 0;
587         uint    cseqoff = 0;
588         uint    cseqlen = 0;
589         uint    lineoff = 0;
590         uint    linelen = 0;
591         uint    off;
592         int     rc;
593         uint    port = 0;
594         struct  ip_conntrack_expect *new_exp = NULL;
595         int     ret = 0;
596
597         if (!rtsp_parse_message(pdata, datalen, &dataoff,
598                                 &hdrsoff, &hdrslen,
599                                 &cseqoff, &cseqlen))
600         {
601             break;      /* not a valid message */
602         }
603
604         if (strncmp(pdata+cmdoff, "PLAY ", 5) == 0)
605         {
606             ip_conntrack_rtsp_proc_play(ct, iph);
607             continue;
608         }
609
610         if (strncmp(pdata+cmdoff, "PAUSE ", 6) == 0)
611         {
612             ip_conntrack_rtsp_proc_pause(ct, iph);
613             continue;
614         }
615
616         if (strncmp(pdata+cmdoff, "TEARDOWN ", 6) == 0)
617         {
618             ip_conntrack_rtsp_proc_teardown(iph);   /* TEARDOWN message */
619             continue;
620         }
621
622         if (strncmp(pdata+cmdoff, "SETUP ", 6) != 0)
623         {
624             continue;   /* not a SETUP message */
625         }
626         DEBUGP("found a setup message\n");
627
628         memset(&exp, 0, sizeof(exp));
629
630         off = 0;
631         
632         while (nf_mime_nextline(pdata+hdrsoff, hdrslen, &off,
633                                 &lineoff, &linelen))
634         {
635             if (linelen == 0)
636             {
637                 break;
638             }
639             if (off > hdrsoff+hdrslen)
640             {
641                 INFOP("!! overrun !!");
642                 break;
643             }
644
645             if (nf_strncasecmp(pdata+hdrsoff+lineoff, "Transport:", 10) == 0)
646             {
647                 rtsp_parse_transport(pdata+hdrsoff+lineoff, linelen,
648                                      &exp.help.exp_rtsp_info);
649             }
650         }
651
652         if (exp.help.exp_rtsp_info.loport == 0)
653         {
654             DEBUGP("no udp transports found\n");
655             continue;   /* no udp transports found */
656         }
657
658         DEBUGP("udp transport found, ports=(%d,%hu,%hu)\n",
659               (int)exp.help.exp_rtsp_info.pbtype,
660               exp.help.exp_rtsp_info.loport,
661               exp.help.exp_rtsp_info.hiport);
662
663         LOCK_BH(&ip_rtsp_lock);
664        /*
665          * Translate the original ports to the NAT ports and note them
666          * down to translate back in the return direction.
667          */
668         if (!(ret = rtsp_client_to_nat_pmap(&exp.help.exp_rtsp_info, iph, ct)))
669         {
670             DEBUGP("Dropping the packet. No more space in the mapping table\n");
671             UNLOCK_BH(&ip_rtsp_lock);
672             return NF_DROP;
673         }
674         port = exp.help.exp_rtsp_info.loport;
675         while (port <= exp.help.exp_rtsp_info.hiport) {
676             /*
677              * Allocate expectation for tracking this connection
678              */
679             new_exp = ip_conntrack_expect_alloc();
680             if (!new_exp) {
681                 INFOP("Failed to get a new expectation entry\n");
682                 UNLOCK_BH(&ip_rtsp_lock);
683                 return NF_DROP;
684             }
685             memcpy(new_exp, &exp, sizeof(struct ip_conntrack_expect));
686             new_exp->seq = ntohl(tcph->seq) + hdrsoff; /* mark all the headers */
687             new_exp->help.exp_rtsp_info.len = hdrslen;
688
689             DEBUGP("Adding UDP port %hu,%hu\n", htons(port), ntohs(port));
690
691             new_exp->tuple = ct->tuplehash[!dir].tuple;
692             if (ret == 2) {
693                     new_exp->tuple.dst.u.udp.port = htons(g_tr_port);
694                     g_tr_port++;
695             } else
696                 new_exp->tuple.dst.u.udp.port = htons(port);
697             new_exp->tuple.dst.protonum = IPPROTO_UDP;
698             new_exp->mask.src.ip  = 0xffffffff;
699             new_exp->mask.dst.ip  = 0xffffffff;
700             //new_exp->mask.dst.u.udp.port  = (exp.help.exp_rtsp_info.pbtype == pb_range) ? 0xfffe : 0xffff;
701             new_exp->mask.dst.u.udp.port  = 0xffff;
702             new_exp->expectfn = rtp_expect;
703             new_exp->mask.dst.protonum  = 0xffff;
704
705             DEBUGP("expect_related %u.%u.%u.%u:%u-%u.%u.%u.%u:%u\n",
706                     NIPQUAD(new_exp->tuple.src.ip),
707                     ntohs(new_exp->tuple.src.u.tcp.port),
708                     NIPQUAD(new_exp->tuple.dst.ip),
709                     ntohs(new_exp->tuple.dst.u.tcp.port));
710
711             /* pass the request off to the nat helper */
712             rc = ip_conntrack_expect_related(new_exp, ct);
713             if (rc == 0)
714             {
715                 DEBUGP("ip_conntrack_expect_related succeeded loport\n");
716             }
717             else
718             {
719                 DEBUGP("ip_conntrack_expect_related loport failed (%d)\n", rc);
720             }
721             port++;
722         }
723         UNLOCK_BH(&ip_rtsp_lock);
724     }
725
726     return NF_ACCEPT;
727 }
728
729 /* inbound packet: server->client */
730 static int
731 help_in(struct tcphdr* tcph, char* pdata, size_t datalen,
732                 struct ip_conntrack* ct, enum ip_conntrack_info ctinfo)
733 {
734     return NF_ACCEPT;
735 }
736
737 static int
738 help(struct sk_buff* skb,
739                 struct ip_conntrack* ct, enum ip_conntrack_info ctinfo)
740 {
741     uint dataoff;
742     struct iphdr *iph = skb->nh.iph;
743     struct tcphdr tcph;
744     char* data;
745     uint datalen;
746
747     /* Until there's been traffic both ways, don't look in packets. */
748     if (ctinfo != IP_CT_ESTABLISHED && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY)
749     {
750         DEBUGP("conntrackinfo = %u\n", ctinfo);
751         return NF_ACCEPT;
752     }
753
754     /* Not whole TCP header? */
755     if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &tcph, sizeof(tcph)) != 0)
756     {
757         return NF_ACCEPT;
758     }
759
760     /* No data? */
761     dataoff = skb->nh.iph->ihl*4 + tcph.doff*4;
762     if ( skb->nh.iph->ihl*4 + tcph.doff*4 >= skb->len)
763     {
764         return NF_ACCEPT;
765     }
766
767     LOCK_BH(&ip_rtsp_lock);
768     skb_copy_bits(skb, dataoff, rtsp_buffer, skb->len - dataoff);
769     data = rtsp_buffer;
770     datalen = skb->len - dataoff;
771     switch (CTINFO2DIR(ctinfo))
772     {
773     case IP_CT_DIR_ORIGINAL:
774         help_out(iph, data, datalen, ct, ctinfo);
775         break;
776     case IP_CT_DIR_REPLY:
777         help_in(&tcph, data, datalen, ct, ctinfo);
778         break;
779     default:
780         /* oops */
781         break;
782     }
783     UNLOCK_BH(&ip_rtsp_lock);
784
785     return NF_ACCEPT;
786 }
787
788 static struct ip_conntrack_helper rtsp_helpers[MAX_PORTS];
789 static char rtsp_names[MAX_PORTS][10];
790
791 static void
792 fini(void)
793 {
794     int i;
795     for (i = 0; i < num_ports; i++)
796     {
797         DEBUGP("unregistering port %d\n", ports[i]);
798         ip_conntrack_helper_unregister(&rtsp_helpers[i]);
799     }
800     for (i = 0; i < MAX_PORT_MAPS; i++)
801     {
802         if (!rtsp_data_ports[i].in_use)
803         {
804             continue;
805         }
806         if (rtsp_data_ports[i].timeout_active == 1) {
807             del_timer(&rtsp_data_ports[i].pause_timeout);
808         }
809     }
810 }
811
812 static int __init
813 init(void)
814 {
815     int i, ret;
816     struct ip_conntrack_helper *hlpr;
817     char *tmpname;
818
819     printk("ip_conntrack_rtsp v" IP_NF_RTSP_VERSION " loading\n");
820
821     if (max_outstanding < 1)
822     {
823         printk("ip_conntrack_rtsp: max_outstanding must be a positive integer\n");
824         return -EBUSY;
825     }
826     if (setup_timeout < 0)
827     {
828         printk("ip_conntrack_rtsp: setup_timeout must be a positive integer\n");
829         return -EBUSY;
830     }
831
832     /* If no port given, default to standard rtsp port */
833     if (ports[0] == 0)
834     {
835         ports[0] = RTSP_PORT;
836     }
837
838     for (i = 0; i < MAX_PORT_MAPS; i++)
839     {
840         memset(&rtsp_data_ports[i], 0, sizeof(struct _rtsp_data_ports));
841         rtsp_data_ports[i].in_use     = 0;
842     }
843
844     for (i = 0; (i < MAX_PORTS) && ports[i]; i++)
845     {
846         hlpr = &rtsp_helpers[i];
847         memset(hlpr, 0, sizeof(struct ip_conntrack_helper));
848         hlpr->tuple.src.u.tcp.port = htons(ports[i]);
849         hlpr->tuple.dst.protonum = IPPROTO_TCP;
850         hlpr->mask.src.u.tcp.port = 0xFFFF;
851         hlpr->mask.dst.protonum = 0xFFFF;
852         hlpr->max_expected = max_outstanding;
853         hlpr->timeout = 0;
854         hlpr->flags = IP_CT_HELPER_F_REUSE_EXPECT;
855         hlpr->me = ip_conntrack_rtsp;
856         hlpr->help = help;
857
858         tmpname = &rtsp_names[i][0];
859         if (ports[i] == RTSP_PORT)
860         {
861             sprintf(tmpname, "rtsp");
862         }
863         else
864         {
865             sprintf(tmpname, "rtsp-%d", i);
866         }
867         hlpr->name = tmpname;
868
869         DEBUGP("port #%d: %d\n", i, ports[i]);
870
871         ret = ip_conntrack_helper_register(hlpr);
872
873         if (ret)
874         {
875             printk("ip_conntrack_rtsp: ERROR registering port %d\n", ports[i]);
876             fini();
877             return -EBUSY;
878         }
879         num_ports++;
880     }
881     return 0;
882 }
883
884 PROVIDES_CONNTRACK(rtsp);
885 EXPORT_SYMBOL(ip_rtsp_lock);
886
887 module_init(init);
888 module_exit(fini);