]> err.no Git - linux-2.6/commitdiff
[NETFILTER]: nf_conntrack_sip: flush expectations on call termination
authorPatrick McHardy <kaber@trash.net>
Wed, 26 Mar 2008 03:24:04 +0000 (20:24 -0700)
committerDavid S. Miller <davem@davemloft.net>
Wed, 26 Mar 2008 03:24:04 +0000 (20:24 -0700)
Flush the RTP expectations we've created when a call is hung up or
terminated otherwise.

Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/netfilter/nf_conntrack_sip.c

index 71f744ad7653f7e0821e7c37a49729d5966e1ddd..8e7e5b465ffb4b41cb0106129bc34e42490fb525 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/netfilter.h>
 
 #include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_core.h>
 #include <net/netfilter/nf_conntrack_expect.h>
 #include <net/netfilter/nf_conntrack_helper.h>
 #include <linux/netfilter/nf_conntrack_sip.h>
@@ -533,6 +534,22 @@ int ct_sip_get_sdp_header(const struct nf_conn *ct, const char *dptr,
 }
 EXPORT_SYMBOL_GPL(ct_sip_get_sdp_header);
 
+static void flush_expectations(struct nf_conn *ct)
+{
+       struct nf_conn_help *help = nfct_help(ct);
+       struct nf_conntrack_expect *exp;
+       struct hlist_node *n, *next;
+
+       spin_lock_bh(&nf_conntrack_lock);
+       hlist_for_each_entry_safe(exp, n, next, &help->expectations, lnode) {
+               if (!del_timer(&exp->timeout))
+                       continue;
+               nf_ct_unlink_expect(exp);
+               nf_ct_expect_put(exp);
+       }
+       spin_unlock_bh(&nf_conntrack_lock);
+}
+
 static int set_expected_rtp(struct sk_buff *skb,
                            const char **dptr, unsigned int *datalen,
                            union nf_inet_addr *addr, __be16 port)
@@ -606,32 +623,58 @@ static int process_invite_response(struct sk_buff *skb,
                                   const char **dptr, unsigned int *datalen,
                                   unsigned int cseq, unsigned int code)
 {
+       enum ip_conntrack_info ctinfo;
+       struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
+
        if ((code >= 100 && code <= 199) ||
            (code >= 200 && code <= 299))
                return process_sdp(skb, dptr, datalen, cseq);
-
-       return NF_ACCEPT;
+       else {
+               flush_expectations(ct);
+               return NF_ACCEPT;
+       }
 }
 
 static int process_update_response(struct sk_buff *skb,
                                   const char **dptr, unsigned int *datalen,
                                   unsigned int cseq, unsigned int code)
 {
+       enum ip_conntrack_info ctinfo;
+       struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
+
        if ((code >= 100 && code <= 199) ||
            (code >= 200 && code <= 299))
                return process_sdp(skb, dptr, datalen, cseq);
-
-       return NF_ACCEPT;
+       else {
+               flush_expectations(ct);
+               return NF_ACCEPT;
+       }
 }
 
 static int process_prack_response(struct sk_buff *skb,
                                  const char **dptr, unsigned int *datalen,
                                  unsigned int cseq, unsigned int code)
 {
+       enum ip_conntrack_info ctinfo;
+       struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
+
        if ((code >= 100 && code <= 199) ||
            (code >= 200 && code <= 299))
                return process_sdp(skb, dptr, datalen, cseq);
+       else {
+               flush_expectations(ct);
+               return NF_ACCEPT;
+       }
+}
+
+static int process_bye_request(struct sk_buff *skb,
+                              const char **dptr, unsigned int *datalen,
+                              unsigned int cseq)
+{
+       enum ip_conntrack_info ctinfo;
+       struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
 
+       flush_expectations(ct);
        return NF_ACCEPT;
 }
 
@@ -640,6 +683,7 @@ static const struct sip_handler sip_handlers[] = {
        SIP_HANDLER("UPDATE", process_sdp, process_update_response),
        SIP_HANDLER("ACK", process_sdp, NULL),
        SIP_HANDLER("PRACK", process_sdp, process_prack_response),
+       SIP_HANDLER("BYE", process_bye_request, NULL),
 };
 
 static int process_sip_response(struct sk_buff *skb,