2 * RTSP extension for IP connection tracking
3 * (C) 2003 by Tom Marshall <tmarshall@real.com>
4 * based on ip_conntrack_irc.c
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.
12 * insmod ip_conntrack_rtsp.o ports=port1,port2,...port<MAX_PORTS>
13 * max_outstanding=n setup_timeout=secs
15 * If no ports are specified, the default will be port 554.
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).
23 #include <linux/config.h>
24 #include <linux/module.h>
25 #include <linux/netfilter.h>
27 #include <linux/udp.h>
28 #include <net/checksum.h>
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>
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>
45 #define MAX_SIMUL_SETUP 8 /* XXX: use max_outstanding */
48 * To enable debugging, replace the line below with #define IP_NF_RTSP_DEBUG 1
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__); \
56 #define DEBUGP(args...)
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;
65 /* This is slow, but it's simple. --RR */
66 static char rtsp_buffer[65536];
68 MODULE_AUTHOR("Tom Marshall <tmarshall@real.com>");
69 MODULE_DESCRIPTION("RTSP connection tracking module");
70 MODULE_LICENSE("GPL");
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");
80 DECLARE_LOCK(ip_rtsp_lock);
81 struct module* ip_conntrack_rtsp = THIS_MODULE;
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.
89 #define MAX_PORT_MAPS 16
90 static u_int16_t g_tr_port = 7000;
92 #define PAUSE_TIMEOUT (5 * HZ)
93 #define RTSP_PAUSE_TIMEOUT (6 * HZ)
95 /*** default port list was here in the masq code: 554, 3030, 4040 ***/
97 #define SKIP_WSPACE(ptr,len,off) while(off < len && isspace(*(ptr+off))) { off++; }
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.
104 struct _rtsp_data_ports {
106 u_int16_t client_tcp_port;
107 u_int16_t client_udp_lo;
108 u_int16_t client_udp_hi;
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;
117 } rtsp_data_ports[MAX_PORT_MAPS];
119 static u_int16_t rtsp_nat_to_client_pmap(u_int16_t nat_port);
122 save_ct(struct ip_conntrack *ct)
125 struct ip_conntrack_tuple *tp = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
127 for (i = 0; i < MAX_PORT_MAPS; i++)
129 if (!rtsp_data_ports[i].in_use)
133 if (rtsp_data_ports[i].nat_udp_lo == ntohs((tp)->dst.u.all))
135 rtsp_data_ports[i].ct_lo = ct;
138 else if (rtsp_data_ports[i].nat_udp_hi == ntohs((tp)->dst.u.all))
140 rtsp_data_ports[i].ct_hi = ct;
147 rtsp_pause_timeout(unsigned long data)
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;
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);
164 ip_conntrack_rtsp_proc_play(struct ip_conntrack *ct, const struct iphdr *iph)
167 struct tcphdr *tcph = (void *)iph + iph->ihl * 4;
169 for (i = 0; i < MAX_PORT_MAPS; i++)
171 if (!rtsp_data_ports[i].in_use)
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))
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)
186 del_timer(&rtsp_data_ports[i].pause_timeout);
187 rtsp_data_ports[i].timeout_active = 0;
194 ip_conntrack_rtsp_proc_pause(struct ip_conntrack *ct, const struct iphdr *iph)
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;
203 for (i = 0; i < MAX_PORT_MAPS; i++)
205 if (!rtsp_data_ports[i].in_use)
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))
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)
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);
237 rtp_expect(struct ip_conntrack *ct)
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);
246 ct->nat.rtsp_info.orig_port = orig_port;
250 DEBUGP("UDP client port %hu\n", ct->nat.rtsp_info.orig_port);
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
263 rtsp_client_to_nat_pmap(struct ip_ct_rtsp_expect *prtspexp, const struct iphdr *iph,
264 struct ip_conntrack *ct)
268 struct tcphdr *tcph = (void *)iph + iph->ihl * 4;
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);
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)
284 prtspexp->loport = rtsp_data_ports[i].nat_udp_lo;
285 prtspexp->hiport = rtsp_data_ports[i].nat_udp_hi;
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));
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.
313 rtsp_nat_to_client_pmap(u_int16_t nat_port)
316 u_int16_t tr_port = 0;
318 for (i = 0; i < MAX_PORT_MAPS; i++) {
319 if (!rtsp_data_ports[i].in_use) {
323 * Check if the UDP ports match any of our NAT ports and return
324 * the client UDP ports.
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);
348 ip_conntrack_rtsp_proc_teardown(struct iphdr *iph)
351 struct tcphdr *tcph = (void *)iph + iph->ihl * 4;
353 for (i = 0; i < MAX_PORT_MAPS; i++)
355 if (!rtsp_data_ports[i].in_use)
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))
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)
370 del_timer(&rtsp_data_ports[i].pause_timeout);
371 rtsp_data_ports[i].timeout_active = 0;
373 memset(&rtsp_data_ports[i], 0, sizeof(struct _rtsp_data_ports));
374 rtsp_data_ports[i].in_use = 0;
381 find_char(void *str, int ch, size_t len)
383 unsigned char *pStr = NULL;
389 return ((void *)(pStr - 1));
391 } while (--len != 0);
396 * Parse an RTSP packet.
398 * Returns zero if parsing failed.
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
410 rtsp_parse_message(char* ptcp, uint tcplen, uint* ptcpoff,
411 uint* phdrsoff, uint* phdrslen,
412 uint* pcseqoff, uint* pcseqlen)
418 if (!nf_nextline(ptcp, tcplen, ptcpoff, &lineoff, &linelen))
423 *phdrsoff = *ptcpoff;
424 while (nf_mime_nextline(ptcp, tcplen, ptcpoff, &lineoff, &linelen))
430 *ptcpoff += min(entitylen, tcplen - *ptcpoff);
434 if (lineoff+linelen > tcplen)
436 INFOP("!! overrun !!\n");
440 if (nf_strncasecmp(ptcp+lineoff, "CSeq:", 5) == 0)
445 if (nf_strncasecmp(ptcp+lineoff, "Content-Length:", 15) == 0)
447 uint off = lineoff+15;
448 SKIP_WSPACE(ptcp+lineoff, linelen, off);
449 nf_strtou32(ptcp+off, &entitylen);
452 *phdrslen = (*ptcpoff) - (*phdrsoff);
458 * Find lo/hi client ports (if any) in transport header
460 * ptcp, tcplen = packet
461 * tranoff, tranlen = buffer to search
464 * pport_lo, pport_hi = lo/hi ports (host endian)
466 * Returns nonzero if any client ports found
468 * Note: it is valid (and expected) for the client to request multiple
469 * transports, so we need to parse the entire line.
472 rtsp_parse_transport(char* ptran, uint tranlen,
473 struct ip_ct_rtsp_expect* prtspexp)
478 if (tranlen < 10 || !iseol(ptran[tranlen-1]) ||
479 nf_strncasecmp(ptran, "Transport:", 10) != 0)
481 INFOP("sanity check failed\n");
484 DEBUGP("tran='%.*s'\n", (int)tranlen, ptran);
486 SKIP_WSPACE(ptran, tranlen, off);
488 /* Transport: tran;field;field=val,tran;field;field=val,... */
489 while (off < tranlen)
491 const char* pparamend;
494 pparamend = find_char(ptran+off, ',', tranlen-off);
495 pparamend = (pparamend == NULL) ? ptran+tranlen : pparamend+1;
496 nextparamoff = pparamend-ptran;
498 while (off < nextparamoff)
500 const char* pfieldend;
503 pfieldend = find_char(ptran+off, ';', nextparamoff-off);
504 nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1;
506 if (strncmp(ptran+off, "client_port=", 12) == 0)
512 numlen = nf_strtou16(ptran+off, &port);
514 if (prtspexp->loport != 0 && prtspexp->loport != port)
516 DEBUGP("multiple ports found, port %hu ignored\n", port);
520 prtspexp->loport = prtspexp->hiport = port;
521 DEBUGP("DASH or SLASH 0x%x\n", ptran[off]);
522 if (ptran[off] == '-')
525 numlen = nf_strtou16(ptran+off, &port);
527 prtspexp->pbtype = pb_range;
528 prtspexp->hiport = port;
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)
535 DEBUGP("incorrect range: %hu-%hu, correcting\n",
536 prtspexp->loport, prtspexp->hiport);
537 prtspexp->loport &= 0xfffe;
538 prtspexp->hiport = prtspexp->loport+1;
541 else if (ptran[off] == '/')
544 numlen = nf_strtou16(ptran+off, &port);
546 prtspexp->pbtype = pb_discon;
547 prtspexp->hiport = port;
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.
569 /*** conntrack functions ***/
571 /* outbound packet: client->server */
573 help_out(struct iphdr* iph, char* pdata, size_t datalen,
574 struct ip_conntrack* ct, enum ip_conntrack_info ctinfo)
576 int dir = CTINFO2DIR(ctinfo); /* = IP_CT_DIR_ORIGINAL */
578 struct tcphdr *tcph = (void *)iph + iph->ihl * 4;
580 struct ip_conntrack_expect exp;
582 while (dataoff < datalen)
584 uint cmdoff = dataoff;
594 struct ip_conntrack_expect *new_exp = NULL;
597 if (!rtsp_parse_message(pdata, datalen, &dataoff,
601 break; /* not a valid message */
604 if (strncmp(pdata+cmdoff, "PLAY ", 5) == 0)
606 ip_conntrack_rtsp_proc_play(ct, iph);
610 if (strncmp(pdata+cmdoff, "PAUSE ", 6) == 0)
612 ip_conntrack_rtsp_proc_pause(ct, iph);
616 if (strncmp(pdata+cmdoff, "TEARDOWN ", 6) == 0)
618 ip_conntrack_rtsp_proc_teardown(iph); /* TEARDOWN message */
622 if (strncmp(pdata+cmdoff, "SETUP ", 6) != 0)
624 continue; /* not a SETUP message */
626 DEBUGP("found a setup message\n");
628 memset(&exp, 0, sizeof(exp));
632 while (nf_mime_nextline(pdata+hdrsoff, hdrslen, &off,
639 if (off > hdrsoff+hdrslen)
641 INFOP("!! overrun !!");
645 if (nf_strncasecmp(pdata+hdrsoff+lineoff, "Transport:", 10) == 0)
647 rtsp_parse_transport(pdata+hdrsoff+lineoff, linelen,
648 &exp.help.exp_rtsp_info);
652 if (exp.help.exp_rtsp_info.loport == 0)
654 DEBUGP("no udp transports found\n");
655 continue; /* no udp transports found */
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);
663 LOCK_BH(&ip_rtsp_lock);
665 * Translate the original ports to the NAT ports and note them
666 * down to translate back in the return direction.
668 if (!(ret = rtsp_client_to_nat_pmap(&exp.help.exp_rtsp_info, iph, ct)))
670 DEBUGP("Dropping the packet. No more space in the mapping table\n");
671 UNLOCK_BH(&ip_rtsp_lock);
674 port = exp.help.exp_rtsp_info.loport;
675 while (port <= exp.help.exp_rtsp_info.hiport) {
677 * Allocate expectation for tracking this connection
679 new_exp = ip_conntrack_expect_alloc();
681 INFOP("Failed to get a new expectation entry\n");
682 UNLOCK_BH(&ip_rtsp_lock);
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;
689 DEBUGP("Adding UDP port %hu,%hu\n", htons(port), ntohs(port));
691 new_exp->tuple = ct->tuplehash[!dir].tuple;
693 new_exp->tuple.dst.u.udp.port = htons(g_tr_port);
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;
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));
711 /* pass the request off to the nat helper */
712 rc = ip_conntrack_expect_related(new_exp, ct);
715 DEBUGP("ip_conntrack_expect_related succeeded loport\n");
719 DEBUGP("ip_conntrack_expect_related loport failed (%d)\n", rc);
723 UNLOCK_BH(&ip_rtsp_lock);
729 /* inbound packet: server->client */
731 help_in(struct tcphdr* tcph, char* pdata, size_t datalen,
732 struct ip_conntrack* ct, enum ip_conntrack_info ctinfo)
738 help(struct sk_buff* skb,
739 struct ip_conntrack* ct, enum ip_conntrack_info ctinfo)
742 struct iphdr *iph = skb->nh.iph;
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)
750 DEBUGP("conntrackinfo = %u\n", ctinfo);
754 /* Not whole TCP header? */
755 if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &tcph, sizeof(tcph)) != 0)
761 dataoff = skb->nh.iph->ihl*4 + tcph.doff*4;
762 if ( skb->nh.iph->ihl*4 + tcph.doff*4 >= skb->len)
767 LOCK_BH(&ip_rtsp_lock);
768 skb_copy_bits(skb, dataoff, rtsp_buffer, skb->len - dataoff);
770 datalen = skb->len - dataoff;
771 switch (CTINFO2DIR(ctinfo))
773 case IP_CT_DIR_ORIGINAL:
774 help_out(iph, data, datalen, ct, ctinfo);
776 case IP_CT_DIR_REPLY:
777 help_in(&tcph, data, datalen, ct, ctinfo);
783 UNLOCK_BH(&ip_rtsp_lock);
788 static struct ip_conntrack_helper rtsp_helpers[MAX_PORTS];
789 static char rtsp_names[MAX_PORTS][10];
795 for (i = 0; i < num_ports; i++)
797 DEBUGP("unregistering port %d\n", ports[i]);
798 ip_conntrack_helper_unregister(&rtsp_helpers[i]);
800 for (i = 0; i < MAX_PORT_MAPS; i++)
802 if (!rtsp_data_ports[i].in_use)
806 if (rtsp_data_ports[i].timeout_active == 1) {
807 del_timer(&rtsp_data_ports[i].pause_timeout);
816 struct ip_conntrack_helper *hlpr;
819 printk("ip_conntrack_rtsp v" IP_NF_RTSP_VERSION " loading\n");
821 if (max_outstanding < 1)
823 printk("ip_conntrack_rtsp: max_outstanding must be a positive integer\n");
826 if (setup_timeout < 0)
828 printk("ip_conntrack_rtsp: setup_timeout must be a positive integer\n");
832 /* If no port given, default to standard rtsp port */
835 ports[0] = RTSP_PORT;
838 for (i = 0; i < MAX_PORT_MAPS; i++)
840 memset(&rtsp_data_ports[i], 0, sizeof(struct _rtsp_data_ports));
841 rtsp_data_ports[i].in_use = 0;
844 for (i = 0; (i < MAX_PORTS) && ports[i]; i++)
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;
854 hlpr->flags = IP_CT_HELPER_F_REUSE_EXPECT;
855 hlpr->me = ip_conntrack_rtsp;
858 tmpname = &rtsp_names[i][0];
859 if (ports[i] == RTSP_PORT)
861 sprintf(tmpname, "rtsp");
865 sprintf(tmpname, "rtsp-%d", i);
867 hlpr->name = tmpname;
869 DEBUGP("port #%d: %d\n", i, ports[i]);
871 ret = ip_conntrack_helper_register(hlpr);
875 printk("ip_conntrack_rtsp: ERROR registering port %d\n", ports[i]);
884 PROVIDES_CONNTRACK(rtsp);
885 EXPORT_SYMBOL(ip_rtsp_lock);