I think hackers chould build a malicious h323 packet to overflow
the pointer p which will panic during the memcpy(addr, p, len)
For example, he may fabricate a very large taddr->ipAddress.ip in
function get_h225_addr.

To avoid above, I add buffer boundary checking both in get addr
functions and set addr functions.

Because the temporary h323 buffer is dynamiclly allocated, I remove
the h323 spin lock in my patch.

Signed-off-by: Zhouyi Zhou <yizhouz...@ict.ac.cn>
---
 include/linux/netfilter/nf_conntrack_h323.h |  17 +-
 net/ipv4/netfilter/nf_nat_h323.c            |  33 ++-
 net/netfilter/nf_conntrack_h323_main.c      | 328 +++++++++++++++++-----------
 3 files changed, 244 insertions(+), 134 deletions(-)

diff --git a/include/linux/netfilter/nf_conntrack_h323.h 
b/include/linux/netfilter/nf_conntrack_h323.h
index 858d9b2..6c6fea1 100644
--- a/include/linux/netfilter/nf_conntrack_h323.h
+++ b/include/linux/netfilter/nf_conntrack_h323.h
@@ -27,11 +27,17 @@ struct nf_ct_h323_master {
        };
 };
 
+struct h323_ct_state {
+       unsigned char *buf;
+       unsigned char *data;
+       int buflen;
+};
+
 struct nf_conn;
 
 int get_h225_addr(struct nf_conn *ct, unsigned char *data,
                  TransportAddress *taddr, union nf_inet_addr *addr,
-                 __be16 *port);
+                 __be16 *port, struct h323_ct_state *ctstate);
 void nf_conntrack_h245_expect(struct nf_conn *new,
                              struct nf_conntrack_expect *this);
 void nf_conntrack_q931_expect(struct nf_conn *new,
@@ -50,12 +56,14 @@ extern int (*set_sig_addr_hook) (struct sk_buff *skb,
                                 struct nf_conn *ct,
                                 enum ip_conntrack_info ctinfo,
                                 unsigned int protoff, unsigned char **data,
-                                TransportAddress *taddr, int count);
+                                TransportAddress *taddr, int count,
+                                struct h323_ct_state *ctstate);
 extern int (*set_ras_addr_hook) (struct sk_buff *skb,
                                 struct nf_conn *ct,
                                 enum ip_conntrack_info ctinfo,
                                 unsigned int protoff, unsigned char **data,
-                                TransportAddress *taddr, int count);
+                                TransportAddress *taddr, int count,
+                                struct h323_ct_state *ctstate);
 extern int (*nat_rtp_rtcp_hook) (struct sk_buff *skb,
                                 struct nf_conn *ct,
                                 enum ip_conntrack_info ctinfo,
@@ -90,7 +98,8 @@ extern int (*nat_q931_hook) (struct sk_buff *skb, struct 
nf_conn *ct,
                             unsigned int protoff,
                             unsigned char **data, TransportAddress *taddr,
                             int idx, __be16 port,
-                            struct nf_conntrack_expect *exp);
+                            struct nf_conntrack_expect *exp,
+                            struct h323_ct_state *ctstate);
 
 #endif
 
diff --git a/net/ipv4/netfilter/nf_nat_h323.c b/net/ipv4/netfilter/nf_nat_h323.c
index 574f7eb..5ed2d70 100644
--- a/net/ipv4/netfilter/nf_nat_h323.c
+++ b/net/ipv4/netfilter/nf_nat_h323.c
@@ -33,12 +33,20 @@ static int set_addr(struct sk_buff *skb, unsigned int 
protoff,
        } __attribute__ ((__packed__)) buf;
        const struct tcphdr *th;
        struct tcphdr _tcph;
+       int datalen;
+       struct iphdr *iph = ip_hdr(skb);
 
        buf.ip = ip;
        buf.port = port;
        addroff += dataoff;
 
        if (ip_hdr(skb)->protocol == IPPROTO_TCP) {
+               th = (void *)iph + iph->ihl * 4;
+               datalen = skb->len - (iph->ihl * 4 + th->doff * 4);
+               /* check offset overflow */
+               if (addroff > datalen)
+                       return  -1;
+
                if (!nf_nat_mangle_tcp_packet(skb, ct, ctinfo,
                                              protoff, addroff, sizeof(buf),
                                              (char *) &buf, sizeof(buf))) {
@@ -53,6 +61,11 @@ static int set_addr(struct sk_buff *skb, unsigned int 
protoff,
                        return -1;
                *data = skb->data + ip_hdrlen(skb) + th->doff * 4 + dataoff;
        } else {
+               datalen = skb->len - (iph->ihl * 4 + sizeof(struct udphdr));
+               /* check offset overflow */
+               if (addroff > datalen)
+                       return  -1;
+
                if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo,
                                              protoff, addroff, sizeof(buf),
                                              (char *) &buf, sizeof(buf))) {
@@ -93,7 +106,8 @@ static int set_h245_addr(struct sk_buff *skb, unsigned 
protoff,
 static int set_sig_addr(struct sk_buff *skb, struct nf_conn *ct,
                        enum ip_conntrack_info ctinfo,
                        unsigned int protoff, unsigned char **data,
-                       TransportAddress *taddr, int count)
+                       TransportAddress *taddr, int count,
+                       struct h323_ct_state *ctstate)
 {
        const struct nf_ct_h323_master *info = nfct_help_data(ct);
        int dir = CTINFO2DIR(ctinfo);
@@ -102,7 +116,8 @@ static int set_sig_addr(struct sk_buff *skb, struct nf_conn 
*ct,
        union nf_inet_addr addr;
 
        for (i = 0; i < count; i++) {
-               if (get_h225_addr(ct, *data, &taddr[i], &addr, &port)) {
+               if (get_h225_addr(ct, *data, &taddr[i], &addr, &port,
+                                 ctstate)) {
                        if (addr.ip == ct->tuplehash[dir].tuple.src.u3.ip &&
                            port == info->sig_port[dir]) {
                                /* GW->GK */
@@ -110,7 +125,7 @@ static int set_sig_addr(struct sk_buff *skb, struct nf_conn 
*ct,
                                /* Fix for Gnomemeeting */
                                if (i > 0 &&
                                    get_h225_addr(ct, *data, &taddr[0],
-                                                 &addr, &port) &&
+                                                 &addr, &port, ctstate) &&
                                    (ntohl(addr.ip) & 0xff000000) == 0x7f000000)
                                        i = 0;
 
@@ -146,7 +161,8 @@ static int set_sig_addr(struct sk_buff *skb, struct nf_conn 
*ct,
 static int set_ras_addr(struct sk_buff *skb, struct nf_conn *ct,
                        enum ip_conntrack_info ctinfo,
                        unsigned int protoff, unsigned char **data,
-                       TransportAddress *taddr, int count)
+                       TransportAddress *taddr, int count,
+                       struct h323_ct_state *ctstate)
 {
        int dir = CTINFO2DIR(ctinfo);
        int i;
@@ -154,7 +170,8 @@ static int set_ras_addr(struct sk_buff *skb, struct nf_conn 
*ct,
        union nf_inet_addr addr;
 
        for (i = 0; i < count; i++) {
-               if (get_h225_addr(ct, *data, &taddr[i], &addr, &port) &&
+               if (get_h225_addr(ct, *data, &taddr[i], &addr, &port,
+                                 ctstate) &&
                    addr.ip == ct->tuplehash[dir].tuple.src.u3.ip &&
                    port == ct->tuplehash[dir].tuple.src.u.udp.port) {
                        pr_debug("nf_nat_ras: set rasAddress 
%pI4:%hu->%pI4:%hu\n",
@@ -424,7 +441,8 @@ static int nat_q931(struct sk_buff *skb, struct nf_conn *ct,
                    enum ip_conntrack_info ctinfo,
                    unsigned int protoff, unsigned char **data,
                    TransportAddress *taddr, int idx,
-                   __be16 port, struct nf_conntrack_expect *exp)
+                   __be16 port, struct nf_conntrack_expect *exp,
+                   struct h323_ct_state *ctstate)
 {
        struct nf_ct_h323_master *info = nfct_help_data(ct);
        int dir = CTINFO2DIR(ctinfo);
@@ -469,7 +487,8 @@ static int nat_q931(struct sk_buff *skb, struct nf_conn *ct,
 
                /* Fix for Gnomemeeting */
                if (idx > 0 &&
-                   get_h225_addr(ct, *data, &taddr[0], &addr, &port) &&
+                   get_h225_addr(ct, *data, &taddr[0], &addr, &port,
+                                 ctstate) &&
                    (ntohl(addr.ip) & 0xff000000) == 0x7f000000) {
                        set_h225_addr(skb, protoff, data, 0, &taddr[0],
                                      &ct->tuplehash[!dir].tuple.dst.u3,
diff --git a/net/netfilter/nf_conntrack_h323_main.c 
b/net/netfilter/nf_conntrack_h323_main.c
index 9511af0..19e797f 100644
--- a/net/netfilter/nf_conntrack_h323_main.c
+++ b/net/netfilter/nf_conntrack_h323_main.c
@@ -64,12 +64,14 @@ int (*set_sig_addr_hook) (struct sk_buff *skb,
                          struct nf_conn *ct,
                          enum ip_conntrack_info ctinfo,
                          unsigned int protoff, unsigned char **data,
-                         TransportAddress *taddr, int count) __read_mostly;
+                         TransportAddress *taddr, int count,
+                         struct h323_ct_state *ctstate) __read_mostly;
 int (*set_ras_addr_hook) (struct sk_buff *skb,
                          struct nf_conn *ct,
                          enum ip_conntrack_info ctinfo,
                          unsigned int protoff, unsigned char **data,
-                         TransportAddress *taddr, int count) __read_mostly;
+                         TransportAddress *taddr, int count,
+                         struct h323_ct_state *ctstate) __read_mostly;
 int (*nat_rtp_rtcp_hook) (struct sk_buff *skb,
                          struct nf_conn *ct,
                          enum ip_conntrack_info ctinfo,
@@ -105,11 +107,10 @@ int (*nat_q931_hook) (struct sk_buff *skb,
                      enum ip_conntrack_info ctinfo,
                      unsigned int protoff,
                      unsigned char **data, TransportAddress *taddr, int idx,
-                     __be16 port, struct nf_conntrack_expect *exp)
+                     __be16 port, struct nf_conntrack_expect *exp,
+                     struct h323_ct_state *ctstate)
                      __read_mostly;
 
-static DEFINE_SPINLOCK(nf_h323_lock);
-static char *h323_buffer;
 
 static struct nf_conntrack_helper nf_conntrack_helper_h245;
 static struct nf_conntrack_helper nf_conntrack_helper_q931[];
@@ -118,7 +119,8 @@ static struct nf_conntrack_helper nf_conntrack_helper_ras[];
 /****************************************************************************/
 static int get_tpkt_data(struct sk_buff *skb, unsigned int protoff,
                         struct nf_conn *ct, enum ip_conntrack_info ctinfo,
-                        unsigned char **data, int *datalen, int *dataoff)
+                        unsigned char **data, int *datalen, int *dataoff,
+                        struct h323_ct_state *ctstate)
 {
        struct nf_ct_h323_master *info = nfct_help_data(ct);
        int dir = CTINFO2DIR(ctinfo);
@@ -145,8 +147,15 @@ static int get_tpkt_data(struct sk_buff *skb, unsigned int 
protoff,
 
        if (*data == NULL) {    /* first TPKT */
                /* Get first TPKT pointer */
+               ctstate->buf = kmalloc(tcpdatalen,  GFP_ATOMIC);
+               if (!ctstate->buf)
+                       return 0;
+
+               ctstate->buflen = tcpdatalen;
+
                tpkt = skb_header_pointer(skb, tcpdataoff, tcpdatalen,
-                                         h323_buffer);
+                                         ctstate->buf);
+               ctstate->data = tpkt;
                BUG_ON(tpkt == NULL);
 
                /* Validate TPKT identifier */
@@ -222,7 +231,8 @@ static int get_tpkt_data(struct sk_buff *skb, unsigned int 
protoff,
 /****************************************************************************/
 static int get_h245_addr(struct nf_conn *ct, const unsigned char *data,
                         H245_TransportAddress *taddr,
-                        union nf_inet_addr *addr, __be16 *port)
+                        union nf_inet_addr *addr, __be16 *port,
+                        struct h323_ct_state *ctstate)
 {
        const unsigned char *p;
        int len;
@@ -247,6 +257,11 @@ static int get_h245_addr(struct nf_conn *ct, const 
unsigned char *data,
                return 0;
        }
 
+       /*check pointer overflow */
+       if (p < ctstate->data ||
+           (p + len + sizeof(__be16)) > ctstate->data + ctstate->buflen)
+               return 0;
+
        memcpy(addr, p, len);
        memset((void *)addr + len, 0, sizeof(*addr) - len);
        memcpy(port, p + len, sizeof(__be16));
@@ -259,7 +274,8 @@ static int expect_rtp_rtcp(struct sk_buff *skb, struct 
nf_conn *ct,
                           enum ip_conntrack_info ctinfo,
                           unsigned int protoff,
                           unsigned char **data, int dataoff,
-                          H245_TransportAddress *taddr)
+                          H245_TransportAddress *taddr,
+                          struct h323_ct_state *ctstate)
 {
        int dir = CTINFO2DIR(ctinfo);
        int ret = 0;
@@ -271,7 +287,7 @@ static int expect_rtp_rtcp(struct sk_buff *skb, struct 
nf_conn *ct,
        typeof(nat_rtp_rtcp_hook) nat_rtp_rtcp;
 
        /* Read RTP or RTCP address */
-       if (!get_h245_addr(ct, *data, taddr, &addr, &port) ||
+       if (!get_h245_addr(ct, *data, taddr, &addr, &port, ctstate) ||
            memcmp(&addr, &ct->tuplehash[dir].tuple.src.u3, sizeof(addr)) ||
            port == 0)
                return 0;
@@ -334,7 +350,8 @@ static int expect_t120(struct sk_buff *skb,
                       enum ip_conntrack_info ctinfo,
                       unsigned int protoff,
                       unsigned char **data, int dataoff,
-                      H245_TransportAddress *taddr)
+                      H245_TransportAddress *taddr,
+                      struct h323_ct_state *ctstate)
 {
        int dir = CTINFO2DIR(ctinfo);
        int ret = 0;
@@ -344,7 +361,7 @@ static int expect_t120(struct sk_buff *skb,
        typeof(nat_t120_hook) nat_t120;
 
        /* Read T.120 address */
-       if (!get_h245_addr(ct, *data, taddr, &addr, &port) ||
+       if (!get_h245_addr(ct, *data, taddr, &addr, &port, ctstate) ||
            memcmp(&addr, &ct->tuplehash[dir].tuple.src.u3, sizeof(addr)) ||
            port == 0)
                return 0;
@@ -386,14 +403,15 @@ static int process_h245_channel(struct sk_buff *skb,
                                enum ip_conntrack_info ctinfo,
                                unsigned int protoff,
                                unsigned char **data, int dataoff,
-                               H2250LogicalChannelParameters *channel)
+                               H2250LogicalChannelParameters *channel,
+                               struct h323_ct_state *ctstate)
 {
        int ret;
 
        if (channel->options & eH2250LogicalChannelParameters_mediaChannel) {
                /* RTP */
                ret = expect_rtp_rtcp(skb, ct, ctinfo, protoff, data, dataoff,
-                                     &channel->mediaChannel);
+                                     &channel->mediaChannel, ctstate);
                if (ret < 0)
                        return -1;
        }
@@ -402,7 +420,7 @@ static int process_h245_channel(struct sk_buff *skb,
            options & eH2250LogicalChannelParameters_mediaControlChannel) {
                /* RTCP */
                ret = expect_rtp_rtcp(skb, ct, ctinfo, protoff, data, dataoff,
-                                     &channel->mediaControlChannel);
+                                     &channel->mediaControlChannel, ctstate);
                if (ret < 0)
                        return -1;
        }
@@ -415,7 +433,8 @@ static int process_olc(struct sk_buff *skb, struct nf_conn 
*ct,
                       enum ip_conntrack_info ctinfo,
                       unsigned int protoff,
                       unsigned char **data, int dataoff,
-                      OpenLogicalChannel *olc)
+                      OpenLogicalChannel *olc,
+                      struct h323_ct_state *ctstate)
 {
        int ret;
 
@@ -429,7 +448,8 @@ static int process_olc(struct sk_buff *skb, struct nf_conn 
*ct,
                                           &olc->
                                           forwardLogicalChannelParameters.
                                           multiplexParameters.
-                                          h2250LogicalChannelParameters);
+                                          h2250LogicalChannelParameters,
+                                          ctstate);
                if (ret < 0)
                        return -1;
        }
@@ -448,7 +468,8 @@ static int process_olc(struct sk_buff *skb, struct nf_conn 
*ct,
                                         &olc->
                                         reverseLogicalChannelParameters.
                                         multiplexParameters.
-                                        h2250LogicalChannelParameters);
+                                        h2250LogicalChannelParameters,
+                                        ctstate);
                if (ret < 0)
                        return -1;
        }
@@ -464,7 +485,8 @@ static int process_olc(struct sk_buff *skb, struct nf_conn 
*ct,
            eNetworkAccessParameters_networkAddress_localAreaAddress) {
                ret = expect_t120(skb, ct, ctinfo, protoff, data, dataoff,
                                  &olc->separateStack.networkAddress.
-                                 localAreaAddress);
+                                 localAreaAddress,
+                                 ctstate);
                if (ret < 0)
                        return -1;
        }
@@ -476,7 +498,8 @@ static int process_olc(struct sk_buff *skb, struct nf_conn 
*ct,
 static int process_olca(struct sk_buff *skb, struct nf_conn *ct,
                        enum ip_conntrack_info ctinfo,
                        unsigned int protoff, unsigned char **data, int dataoff,
-                       OpenLogicalChannelAck *olca)
+                       OpenLogicalChannelAck *olca,
+                       struct h323_ct_state *ctstate)
 {
        H2250LogicalChannelAckParameters *ack;
        int ret;
@@ -496,7 +519,8 @@ static int process_olca(struct sk_buff *skb, struct nf_conn 
*ct,
                                           &olca->
                                           reverseLogicalChannelParameters.
                                           multiplexParameters.
-                                          h2250LogicalChannelParameters);
+                                          h2250LogicalChannelParameters,
+                                          ctstate);
                if (ret < 0)
                        return -1;
        }
@@ -513,7 +537,8 @@ static int process_olca(struct sk_buff *skb, struct nf_conn 
*ct,
                        /* RTP */
                        ret = expect_rtp_rtcp(skb, ct, ctinfo,
                                              protoff, data, dataoff,
-                                             &ack->mediaChannel);
+                                             &ack->mediaChannel,
+                                             ctstate);
                        if (ret < 0)
                                return -1;
                }
@@ -523,7 +548,8 @@ static int process_olca(struct sk_buff *skb, struct nf_conn 
*ct,
                        /* RTCP */
                        ret = expect_rtp_rtcp(skb, ct, ctinfo,
                                              protoff, data, dataoff,
-                                             &ack->mediaControlChannel);
+                                             &ack->mediaControlChannel,
+                                             ctstate);
                        if (ret < 0)
                                return -1;
                }
@@ -534,7 +560,8 @@ static int process_olca(struct sk_buff *skb, struct nf_conn 
*ct,
                eNetworkAccessParameters_networkAddress_localAreaAddress) {
                ret = expect_t120(skb, ct, ctinfo, protoff, data, dataoff,
                                  &olca->separateStack.networkAddress.
-                                 localAreaAddress);
+                                 localAreaAddress,
+                                 ctstate);
                if (ret < 0)
                        return -1;
        }
@@ -546,7 +573,8 @@ static int process_olca(struct sk_buff *skb, struct nf_conn 
*ct,
 static int process_h245(struct sk_buff *skb, struct nf_conn *ct,
                        enum ip_conntrack_info ctinfo,
                        unsigned int protoff, unsigned char **data, int dataoff,
-                       MultimediaSystemControlMessage *mscm)
+                       MultimediaSystemControlMessage *mscm,
+                       struct h323_ct_state *ctstate)
 {
        switch (mscm->choice) {
        case eMultimediaSystemControlMessage_request:
@@ -554,7 +582,8 @@ static int process_h245(struct sk_buff *skb, struct nf_conn 
*ct,
                    eRequestMessage_openLogicalChannel) {
                        return process_olc(skb, ct, ctinfo,
                                           protoff, data, dataoff,
-                                          &mscm->request.openLogicalChannel);
+                                          &mscm->request.openLogicalChannel,
+                                          ctstate);
                }
                pr_debug("nf_ct_h323: H.245 Request %d\n",
                         mscm->request.choice);
@@ -565,7 +594,8 @@ static int process_h245(struct sk_buff *skb, struct nf_conn 
*ct,
                        return process_olca(skb, ct, ctinfo,
                                            protoff, data, dataoff,
                                            &mscm->response.
-                                           openLogicalChannelAck);
+                                           openLogicalChannelAck,
+                                           ctstate);
                }
                pr_debug("nf_ct_h323: H.245 Response %d\n",
                         mscm->response.choice);
@@ -587,6 +617,7 @@ static int h245_help(struct sk_buff *skb, unsigned int 
protoff,
        int datalen;
        int dataoff;
        int ret;
+       struct h323_ct_state ctstate = {NULL, NULL, 0};
 
        /* Until there's been traffic both ways, don't look in packets. */
        if (ctinfo != IP_CT_ESTABLISHED && ctinfo != IP_CT_ESTABLISHED_REPLY)
@@ -594,11 +625,10 @@ static int h245_help(struct sk_buff *skb, unsigned int 
protoff,
 
        pr_debug("nf_ct_h245: skblen = %u\n", skb->len);
 
-       spin_lock_bh(&nf_h323_lock);
 
        /* Process each TPKT */
        while (get_tpkt_data(skb, protoff, ct, ctinfo,
-                            &data, &datalen, &dataoff)) {
+                            &data, &datalen, &dataoff, &ctstate)) {
                pr_debug("nf_ct_h245: TPKT len=%d ", datalen);
                nf_ct_dump_tuple(&ct->tuplehash[CTINFO2DIR(ctinfo)].tuple);
 
@@ -615,15 +645,15 @@ static int h245_help(struct sk_buff *skb, unsigned int 
protoff,
 
                /* Process H.245 signal */
                if (process_h245(skb, ct, ctinfo, protoff,
-                                &data, dataoff, &mscm) < 0)
+                                &data, dataoff, &mscm, &ctstate) < 0)
                        goto drop;
        }
 
-       spin_unlock_bh(&nf_h323_lock);
+       kfree(ctstate.buf);
        return NF_ACCEPT;
 
       drop:
-       spin_unlock_bh(&nf_h323_lock);
+       kfree(ctstate.buf);
        nf_ct_helper_log(skb, ct, "cannot process H.245 message");
        return NF_DROP;
 }
@@ -647,7 +677,8 @@ static struct nf_conntrack_helper nf_conntrack_helper_h245 
__read_mostly = {
 /****************************************************************************/
 int get_h225_addr(struct nf_conn *ct, unsigned char *data,
                  TransportAddress *taddr,
-                 union nf_inet_addr *addr, __be16 *port)
+                 union nf_inet_addr *addr, __be16 *port,
+                 struct h323_ct_state *ctstate)
 {
        const unsigned char *p;
        int len;
@@ -669,6 +700,11 @@ int get_h225_addr(struct nf_conn *ct, unsigned char *data,
                return 0;
        }
 
+               /*check pointer overflow */
+       if (p < ctstate->data ||
+           (p + len + sizeof(__be16)) > ctstate->data + ctstate->buflen)
+               return 0;
+
        memcpy(addr, p, len);
        memset((void *)addr + len, 0, sizeof(*addr) - len);
        memcpy(port, p + len, sizeof(__be16));
@@ -680,7 +716,8 @@ int get_h225_addr(struct nf_conn *ct, unsigned char *data,
 static int expect_h245(struct sk_buff *skb, struct nf_conn *ct,
                       enum ip_conntrack_info ctinfo,
                       unsigned int protoff, unsigned char **data, int dataoff,
-                      TransportAddress *taddr)
+                      TransportAddress *taddr,
+                      struct h323_ct_state *ctstate)
 {
        int dir = CTINFO2DIR(ctinfo);
        int ret = 0;
@@ -690,7 +727,7 @@ static int expect_h245(struct sk_buff *skb, struct nf_conn 
*ct,
        typeof(nat_h245_hook) nat_h245;
 
        /* Read h245Address */
-       if (!get_h225_addr(ct, *data, taddr, &addr, &port) ||
+       if (!get_h225_addr(ct, *data, taddr, &addr, &port, ctstate) ||
            memcmp(&addr, &ct->tuplehash[dir].tuple.src.u3, sizeof(addr)) ||
            port == 0)
                return 0;
@@ -801,7 +838,8 @@ static int expect_callforwarding(struct sk_buff *skb,
                                 enum ip_conntrack_info ctinfo,
                                 unsigned int protoff,
                                 unsigned char **data, int dataoff,
-                                TransportAddress *taddr)
+                                TransportAddress *taddr,
+                                struct h323_ct_state *ctstate)
 {
        int dir = CTINFO2DIR(ctinfo);
        int ret = 0;
@@ -812,7 +850,8 @@ static int expect_callforwarding(struct sk_buff *skb,
        typeof(nat_callforwarding_hook) nat_callforwarding;
 
        /* Read alternativeAddress */
-       if (!get_h225_addr(ct, *data, taddr, &addr, &port) || port == 0)
+       if (!get_h225_addr(ct, *data, taddr, &addr, &port, ctstate)
+           || port == 0)
                return 0;
 
        /* If the calling party is on the same side of the forward-to party,
@@ -860,7 +899,7 @@ static int process_setup(struct sk_buff *skb, struct 
nf_conn *ct,
                         enum ip_conntrack_info ctinfo,
                         unsigned int protoff,
                         unsigned char **data, int dataoff,
-                        Setup_UUIE *setup)
+                        Setup_UUIE *setup, struct h323_ct_state *ctstate)
 {
        int dir = CTINFO2DIR(ctinfo);
        int ret;
@@ -873,7 +912,7 @@ static int process_setup(struct sk_buff *skb, struct 
nf_conn *ct,
 
        if (setup->options & eSetup_UUIE_h245Address) {
                ret = expect_h245(skb, ct, ctinfo, protoff, data, dataoff,
-                                 &setup->h245Address);
+                                 &setup->h245Address, ctstate);
                if (ret < 0)
                        return -1;
        }
@@ -883,7 +922,7 @@ static int process_setup(struct sk_buff *skb, struct 
nf_conn *ct,
            (set_h225_addr) && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
            ct->status & IPS_NAT_MASK &&
            get_h225_addr(ct, *data, &setup->destCallSignalAddress,
-                         &addr, &port) &&
+                         &addr, &port, ctstate) &&
            memcmp(&addr, &ct->tuplehash[!dir].tuple.src.u3, sizeof(addr))) {
                pr_debug("nf_ct_q931: set destCallSignalAddress 
%pI6:%hu->%pI6:%hu\n",
                         &addr, ntohs(port), &ct->tuplehash[!dir].tuple.src.u3,
@@ -900,7 +939,7 @@ static int process_setup(struct sk_buff *skb, struct 
nf_conn *ct,
            (set_h225_addr) && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
            ct->status & IPS_NAT_MASK &&
            get_h225_addr(ct, *data, &setup->sourceCallSignalAddress,
-                         &addr, &port) &&
+                         &addr, &port, ctstate) &&
            memcmp(&addr, &ct->tuplehash[!dir].tuple.dst.u3, sizeof(addr))) {
                pr_debug("nf_ct_q931: set sourceCallSignalAddress 
%pI6:%hu->%pI6:%hu\n",
                         &addr, ntohs(port), &ct->tuplehash[!dir].tuple.dst.u3,
@@ -917,7 +956,8 @@ static int process_setup(struct sk_buff *skb, struct 
nf_conn *ct,
                for (i = 0; i < setup->fastStart.count; i++) {
                        ret = process_olc(skb, ct, ctinfo,
                                          protoff, data, dataoff,
-                                         &setup->fastStart.item[i]);
+                                         &setup->fastStart.item[i],
+                                         ctstate);
                        if (ret < 0)
                                return -1;
                }
@@ -932,7 +972,8 @@ static int process_callproceeding(struct sk_buff *skb,
                                  enum ip_conntrack_info ctinfo,
                                  unsigned int protoff,
                                  unsigned char **data, int dataoff,
-                                 CallProceeding_UUIE *callproc)
+                                 CallProceeding_UUIE *callproc,
+                                 struct h323_ct_state *ctstate)
 {
        int ret;
        int i;
@@ -941,7 +982,7 @@ static int process_callproceeding(struct sk_buff *skb,
 
        if (callproc->options & eCallProceeding_UUIE_h245Address) {
                ret = expect_h245(skb, ct, ctinfo, protoff, data, dataoff,
-                                 &callproc->h245Address);
+                                 &callproc->h245Address, ctstate);
                if (ret < 0)
                        return -1;
        }
@@ -950,7 +991,8 @@ static int process_callproceeding(struct sk_buff *skb,
                for (i = 0; i < callproc->fastStart.count; i++) {
                        ret = process_olc(skb, ct, ctinfo,
                                          protoff, data, dataoff,
-                                         &callproc->fastStart.item[i]);
+                                         &callproc->fastStart.item[i],
+                                         ctstate);
                        if (ret < 0)
                                return -1;
                }
@@ -964,7 +1006,8 @@ static int process_connect(struct sk_buff *skb, struct 
nf_conn *ct,
                           enum ip_conntrack_info ctinfo,
                           unsigned int protoff,
                           unsigned char **data, int dataoff,
-                          Connect_UUIE *connect)
+                          Connect_UUIE *connect,
+                          struct h323_ct_state *ctstate)
 {
        int ret;
        int i;
@@ -973,7 +1016,7 @@ static int process_connect(struct sk_buff *skb, struct 
nf_conn *ct,
 
        if (connect->options & eConnect_UUIE_h245Address) {
                ret = expect_h245(skb, ct, ctinfo, protoff, data, dataoff,
-                                 &connect->h245Address);
+                                 &connect->h245Address, ctstate);
                if (ret < 0)
                        return -1;
        }
@@ -982,7 +1025,8 @@ static int process_connect(struct sk_buff *skb, struct 
nf_conn *ct,
                for (i = 0; i < connect->fastStart.count; i++) {
                        ret = process_olc(skb, ct, ctinfo,
                                          protoff, data, dataoff,
-                                         &connect->fastStart.item[i]);
+                                         &connect->fastStart.item[i],
+                                         ctstate);
                        if (ret < 0)
                                return -1;
                }
@@ -996,7 +1040,7 @@ static int process_alerting(struct sk_buff *skb, struct 
nf_conn *ct,
                            enum ip_conntrack_info ctinfo,
                            unsigned int protoff,
                            unsigned char **data, int dataoff,
-                           Alerting_UUIE *alert)
+                           Alerting_UUIE *alert, struct h323_ct_state *ctstate)
 {
        int ret;
        int i;
@@ -1005,7 +1049,7 @@ static int process_alerting(struct sk_buff *skb, struct 
nf_conn *ct,
 
        if (alert->options & eAlerting_UUIE_h245Address) {
                ret = expect_h245(skb, ct, ctinfo, protoff, data, dataoff,
-                                 &alert->h245Address);
+                                 &alert->h245Address, ctstate);
                if (ret < 0)
                        return -1;
        }
@@ -1014,7 +1058,8 @@ static int process_alerting(struct sk_buff *skb, struct 
nf_conn *ct,
                for (i = 0; i < alert->fastStart.count; i++) {
                        ret = process_olc(skb, ct, ctinfo,
                                          protoff, data, dataoff,
-                                         &alert->fastStart.item[i]);
+                                         &alert->fastStart.item[i],
+                                         ctstate);
                        if (ret < 0)
                                return -1;
                }
@@ -1028,7 +1073,8 @@ static int process_facility(struct sk_buff *skb, struct 
nf_conn *ct,
                            enum ip_conntrack_info ctinfo,
                            unsigned int protoff,
                            unsigned char **data, int dataoff,
-                           Facility_UUIE *facility)
+                           Facility_UUIE *facility,
+                           struct h323_ct_state *ctstate)
 {
        int ret;
        int i;
@@ -1040,13 +1086,14 @@ static int process_facility(struct sk_buff *skb, struct 
nf_conn *ct,
                        return expect_callforwarding(skb, ct, ctinfo,
                                                     protoff, data, dataoff,
                                                     &facility->
-                                                    alternativeAddress);
+                                                    alternativeAddress,
+                                                    ctstate);
                return 0;
        }
 
        if (facility->options & eFacility_UUIE_h245Address) {
                ret = expect_h245(skb, ct, ctinfo, protoff, data, dataoff,
-                                 &facility->h245Address);
+                                 &facility->h245Address, ctstate);
                if (ret < 0)
                        return -1;
        }
@@ -1055,7 +1102,8 @@ static int process_facility(struct sk_buff *skb, struct 
nf_conn *ct,
                for (i = 0; i < facility->fastStart.count; i++) {
                        ret = process_olc(skb, ct, ctinfo,
                                          protoff, data, dataoff,
-                                         &facility->fastStart.item[i]);
+                                         &facility->fastStart.item[i],
+                                         ctstate);
                        if (ret < 0)
                                return -1;
                }
@@ -1069,7 +1117,8 @@ static int process_progress(struct sk_buff *skb, struct 
nf_conn *ct,
                            enum ip_conntrack_info ctinfo,
                            unsigned int protoff,
                            unsigned char **data, int dataoff,
-                           Progress_UUIE *progress)
+                           Progress_UUIE *progress,
+                           struct h323_ct_state *ctstate)
 {
        int ret;
        int i;
@@ -1078,7 +1127,7 @@ static int process_progress(struct sk_buff *skb, struct 
nf_conn *ct,
 
        if (progress->options & eProgress_UUIE_h245Address) {
                ret = expect_h245(skb, ct, ctinfo, protoff, data, dataoff,
-                                 &progress->h245Address);
+                                 &progress->h245Address, ctstate);
                if (ret < 0)
                        return -1;
        }
@@ -1087,7 +1136,8 @@ static int process_progress(struct sk_buff *skb, struct 
nf_conn *ct,
                for (i = 0; i < progress->fastStart.count; i++) {
                        ret = process_olc(skb, ct, ctinfo,
                                          protoff, data, dataoff,
-                                         &progress->fastStart.item[i]);
+                                         &progress->fastStart.item[i],
+                                         ctstate);
                        if (ret < 0)
                                return -1;
                }
@@ -1100,7 +1150,7 @@ static int process_progress(struct sk_buff *skb, struct 
nf_conn *ct,
 static int process_q931(struct sk_buff *skb, struct nf_conn *ct,
                        enum ip_conntrack_info ctinfo,
                        unsigned int protoff, unsigned char **data, int dataoff,
-                       Q931 *q931)
+                       Q931 *q931, struct h323_ct_state *ctstate)
 {
        H323_UU_PDU *pdu = &q931->UUIE.h323_uu_pdu;
        int i;
@@ -1109,29 +1159,35 @@ static int process_q931(struct sk_buff *skb, struct 
nf_conn *ct,
        switch (pdu->h323_message_body.choice) {
        case eH323_UU_PDU_h323_message_body_setup:
                ret = process_setup(skb, ct, ctinfo, protoff, data, dataoff,
-                                   &pdu->h323_message_body.setup);
+                                   &pdu->h323_message_body.setup,
+                                   ctstate);
                break;
        case eH323_UU_PDU_h323_message_body_callProceeding:
                ret = process_callproceeding(skb, ct, ctinfo,
                                             protoff, data, dataoff,
                                             &pdu->h323_message_body.
-                                            callProceeding);
+                                            callProceeding,
+                                            ctstate);
                break;
        case eH323_UU_PDU_h323_message_body_connect:
                ret = process_connect(skb, ct, ctinfo, protoff, data, dataoff,
-                                     &pdu->h323_message_body.connect);
+                                     &pdu->h323_message_body.connect,
+                                     ctstate);
                break;
        case eH323_UU_PDU_h323_message_body_alerting:
                ret = process_alerting(skb, ct, ctinfo, protoff, data, dataoff,
-                                      &pdu->h323_message_body.alerting);
+                                      &pdu->h323_message_body.alerting,
+                                      ctstate);
                break;
        case eH323_UU_PDU_h323_message_body_facility:
                ret = process_facility(skb, ct, ctinfo, protoff, data, dataoff,
-                                      &pdu->h323_message_body.facility);
+                                      &pdu->h323_message_body.facility,
+                                      ctstate);
                break;
        case eH323_UU_PDU_h323_message_body_progress:
                ret = process_progress(skb, ct, ctinfo, protoff, data, dataoff,
-                                      &pdu->h323_message_body.progress);
+                                      &pdu->h323_message_body.progress,
+                                      ctstate);
                break;
        default:
                pr_debug("nf_ct_q931: Q.931 signal %d\n",
@@ -1146,7 +1202,8 @@ static int process_q931(struct sk_buff *skb, struct 
nf_conn *ct,
                for (i = 0; i < pdu->h245Control.count; i++) {
                        ret = process_h245(skb, ct, ctinfo,
                                           protoff, data, dataoff,
-                                          &pdu->h245Control.item[i]);
+                                          &pdu->h245Control.item[i],
+                                          ctstate);
                        if (ret < 0)
                                return -1;
                }
@@ -1164,6 +1221,7 @@ static int q931_help(struct sk_buff *skb, unsigned int 
protoff,
        int datalen;
        int dataoff;
        int ret;
+       struct h323_ct_state ctstate = {NULL, NULL, 0};
 
        /* Until there's been traffic both ways, don't look in packets. */
        if (ctinfo != IP_CT_ESTABLISHED && ctinfo != IP_CT_ESTABLISHED_REPLY)
@@ -1171,11 +1229,10 @@ static int q931_help(struct sk_buff *skb, unsigned int 
protoff,
 
        pr_debug("nf_ct_q931: skblen = %u\n", skb->len);
 
-       spin_lock_bh(&nf_h323_lock);
 
        /* Process each TPKT */
        while (get_tpkt_data(skb, protoff, ct, ctinfo,
-                            &data, &datalen, &dataoff)) {
+                            &data, &datalen, &dataoff, &ctstate)) {
                pr_debug("nf_ct_q931: TPKT len=%d ", datalen);
                nf_ct_dump_tuple(&ct->tuplehash[CTINFO2DIR(ctinfo)].tuple);
 
@@ -1191,15 +1248,16 @@ static int q931_help(struct sk_buff *skb, unsigned int 
protoff,
 
                /* Process Q.931 signal */
                if (process_q931(skb, ct, ctinfo, protoff,
-                                &data, dataoff, &q931) < 0)
+                                &data, dataoff, &q931, &ctstate) < 0)
                        goto drop;
        }
 
-       spin_unlock_bh(&nf_h323_lock);
+       kfree(ctstate.buf);
        return NF_ACCEPT;
 
       drop:
-       spin_unlock_bh(&nf_h323_lock);
+       kfree(ctstate.buf);
+
        nf_ct_helper_log(skb, ct, "cannot process Q.931 message");
        return NF_DROP;
 }
@@ -1235,7 +1293,7 @@ static struct nf_conntrack_helper 
nf_conntrack_helper_q931[] __read_mostly = {
 
 /****************************************************************************/
 static unsigned char *get_udp_data(struct sk_buff *skb, unsigned int protoff,
-                                  int *datalen)
+                                  int *datalen, struct h323_ct_state *ctstate)
 {
        const struct udphdr *uh;
        struct udphdr _uh;
@@ -1248,7 +1306,15 @@ static unsigned char *get_udp_data(struct sk_buff *skb, 
unsigned int protoff,
        if (dataoff >= skb->len)
                return NULL;
        *datalen = skb->len - dataoff;
-       return skb_header_pointer(skb, dataoff, *datalen, h323_buffer);
+
+       ctstate->buf = kmalloc(*datalen, GFP_ATOMIC);
+       if (!ctstate->buf)
+               return NULL;
+
+       ctstate->buflen = *datalen;
+       ctstate->data = skb_header_pointer(skb, dataoff, *datalen,
+                                          ctstate->buf);
+       return ctstate->data;
 }
 
 /****************************************************************************/
@@ -1289,7 +1355,8 @@ static int set_expect_timeout(struct nf_conntrack_expect 
*exp,
 static int expect_q931(struct sk_buff *skb, struct nf_conn *ct,
                       enum ip_conntrack_info ctinfo,
                       unsigned int protoff, unsigned char **data,
-                      TransportAddress *taddr, int count)
+                      TransportAddress *taddr, int count,
+                      struct h323_ct_state *ctstate)
 {
        struct nf_ct_h323_master *info = nfct_help_data(ct);
        int dir = CTINFO2DIR(ctinfo);
@@ -1302,7 +1369,8 @@ static int expect_q931(struct sk_buff *skb, struct 
nf_conn *ct,
 
        /* Look for the first related address */
        for (i = 0; i < count; i++) {
-               if (get_h225_addr(ct, *data, &taddr[i], &addr, &port) &&
+               if (get_h225_addr(ct, *data, &taddr[i], &addr, &port,
+                                 ctstate) &&
                    memcmp(&addr, &ct->tuplehash[dir].tuple.src.u3,
                           sizeof(addr)) == 0 && port != 0)
                        break;
@@ -1326,7 +1394,7 @@ static int expect_q931(struct sk_buff *skb, struct 
nf_conn *ct,
        if (nat_q931 && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
            ct->status & IPS_NAT_MASK) {        /* Need NAT */
                ret = nat_q931(skb, ct, ctinfo, protoff, data,
-                              taddr, i, port, exp);
+                              taddr, i, port, exp, ctstate);
        } else {                /* Conntrack only */
                if (nf_ct_expect_related(exp) == 0) {
                        pr_debug("nf_ct_ras: expect Q.931 ");
@@ -1347,7 +1415,8 @@ static int expect_q931(struct sk_buff *skb, struct 
nf_conn *ct,
 static int process_grq(struct sk_buff *skb, struct nf_conn *ct,
                       enum ip_conntrack_info ctinfo,
                       unsigned int protoff,
-                      unsigned char **data, GatekeeperRequest *grq)
+                      unsigned char **data, GatekeeperRequest *grq,
+                      struct h323_ct_state *ctstate)
 {
        typeof(set_ras_addr_hook) set_ras_addr;
 
@@ -1357,7 +1426,7 @@ static int process_grq(struct sk_buff *skb, struct 
nf_conn *ct,
        if (set_ras_addr && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
            ct->status & IPS_NAT_MASK)  /* NATed */
                return set_ras_addr(skb, ct, ctinfo, protoff, data,
-                                   &grq->rasAddress, 1);
+                                   &grq->rasAddress, 1, ctstate);
        return 0;
 }
 
@@ -1365,7 +1434,8 @@ static int process_grq(struct sk_buff *skb, struct 
nf_conn *ct,
 static int process_gcf(struct sk_buff *skb, struct nf_conn *ct,
                       enum ip_conntrack_info ctinfo,
                       unsigned int protoff,
-                      unsigned char **data, GatekeeperConfirm *gcf)
+                      unsigned char **data, GatekeeperConfirm *gcf,
+                      struct h323_ct_state *ctstate)
 {
        int dir = CTINFO2DIR(ctinfo);
        int ret = 0;
@@ -1375,7 +1445,7 @@ static int process_gcf(struct sk_buff *skb, struct 
nf_conn *ct,
 
        pr_debug("nf_ct_ras: GCF\n");
 
-       if (!get_h225_addr(ct, *data, &gcf->rasAddress, &addr, &port))
+       if (!get_h225_addr(ct, *data, &gcf->rasAddress, &addr, &port, ctstate))
                return 0;
 
        /* Registration port is the same as discovery port */
@@ -1410,7 +1480,8 @@ static int process_gcf(struct sk_buff *skb, struct 
nf_conn *ct,
 static int process_rrq(struct sk_buff *skb, struct nf_conn *ct,
                       enum ip_conntrack_info ctinfo,
                       unsigned int protoff,
-                      unsigned char **data, RegistrationRequest *rrq)
+                      unsigned char **data, RegistrationRequest *rrq,
+                      struct h323_ct_state *ctstate)
 {
        struct nf_ct_h323_master *info = nfct_help_data(ct);
        int ret;
@@ -1420,7 +1491,8 @@ static int process_rrq(struct sk_buff *skb, struct 
nf_conn *ct,
 
        ret = expect_q931(skb, ct, ctinfo, protoff, data,
                          rrq->callSignalAddress.item,
-                         rrq->callSignalAddress.count);
+                         rrq->callSignalAddress.count,
+                         ctstate);
        if (ret < 0)
                return -1;
 
@@ -1429,7 +1501,8 @@ static int process_rrq(struct sk_buff *skb, struct 
nf_conn *ct,
            ct->status & IPS_NAT_MASK) {
                ret = set_ras_addr(skb, ct, ctinfo, protoff, data,
                                   rrq->rasAddress.item,
-                                  rrq->rasAddress.count);
+                                  rrq->rasAddress.count,
+                                  ctstate);
                if (ret < 0)
                        return -1;
        }
@@ -1447,7 +1520,8 @@ static int process_rrq(struct sk_buff *skb, struct 
nf_conn *ct,
 static int process_rcf(struct sk_buff *skb, struct nf_conn *ct,
                       enum ip_conntrack_info ctinfo,
                       unsigned int protoff,
-                      unsigned char **data, RegistrationConfirm *rcf)
+                      unsigned char **data, RegistrationConfirm *rcf,
+                      struct h323_ct_state *ctstate)
 {
        struct nf_ct_h323_master *info = nfct_help_data(ct);
        int dir = CTINFO2DIR(ctinfo);
@@ -1461,8 +1535,9 @@ static int process_rcf(struct sk_buff *skb, struct 
nf_conn *ct,
        if (set_sig_addr && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
            ct->status & IPS_NAT_MASK) {
                ret = set_sig_addr(skb, ct, ctinfo, protoff, data,
-                                       rcf->callSignalAddress.item,
-                                       rcf->callSignalAddress.count);
+                                  rcf->callSignalAddress.item,
+                                  rcf->callSignalAddress.count,
+                                  ctstate);
                if (ret < 0)
                        return -1;
        }
@@ -1498,7 +1573,8 @@ static int process_rcf(struct sk_buff *skb, struct 
nf_conn *ct,
 static int process_urq(struct sk_buff *skb, struct nf_conn *ct,
                       enum ip_conntrack_info ctinfo,
                       unsigned int protoff,
-                      unsigned char **data, UnregistrationRequest *urq)
+                      unsigned char **data, UnregistrationRequest *urq,
+                      struct h323_ct_state *ctstate)
 {
        struct nf_ct_h323_master *info = nfct_help_data(ct);
        int dir = CTINFO2DIR(ctinfo);
@@ -1512,7 +1588,8 @@ static int process_urq(struct sk_buff *skb, struct 
nf_conn *ct,
            ct->status & IPS_NAT_MASK) {
                ret = set_sig_addr(skb, ct, ctinfo, protoff, data,
                                   urq->callSignalAddress.item,
-                                  urq->callSignalAddress.count);
+                                  urq->callSignalAddress.count,
+                                  ctstate);
                if (ret < 0)
                        return -1;
        }
@@ -1532,7 +1609,8 @@ static int process_urq(struct sk_buff *skb, struct 
nf_conn *ct,
 static int process_arq(struct sk_buff *skb, struct nf_conn *ct,
                       enum ip_conntrack_info ctinfo,
                       unsigned int protoff,
-                      unsigned char **data, AdmissionRequest *arq)
+                      unsigned char **data, AdmissionRequest *arq,
+                      struct h323_ct_state *ctstate)
 {
        const struct nf_ct_h323_master *info = nfct_help_data(ct);
        int dir = CTINFO2DIR(ctinfo);
@@ -1545,7 +1623,7 @@ static int process_arq(struct sk_buff *skb, struct 
nf_conn *ct,
        set_h225_addr = rcu_dereference(set_h225_addr_hook);
        if ((arq->options & eAdmissionRequest_destCallSignalAddress) &&
            get_h225_addr(ct, *data, &arq->destCallSignalAddress,
-                         &addr, &port) &&
+                         &addr, &port, ctstate) &&
            !memcmp(&addr, &ct->tuplehash[dir].tuple.src.u3, sizeof(addr)) &&
            port == info->sig_port[dir] &&
            nf_ct_l3num(ct) == NFPROTO_IPV4 &&
@@ -1559,7 +1637,7 @@ static int process_arq(struct sk_buff *skb, struct 
nf_conn *ct,
 
        if ((arq->options & eAdmissionRequest_srcCallSignalAddress) &&
            get_h225_addr(ct, *data, &arq->srcCallSignalAddress,
-                         &addr, &port) &&
+                         &addr, &port, ctstate) &&
            !memcmp(&addr, &ct->tuplehash[dir].tuple.src.u3, sizeof(addr)) &&
            set_h225_addr && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
            ct->status & IPS_NAT_MASK) {
@@ -1577,7 +1655,8 @@ static int process_arq(struct sk_buff *skb, struct 
nf_conn *ct,
 static int process_acf(struct sk_buff *skb, struct nf_conn *ct,
                       enum ip_conntrack_info ctinfo,
                       unsigned int protoff,
-                      unsigned char **data, AdmissionConfirm *acf)
+                      unsigned char **data, AdmissionConfirm *acf,
+                      struct h323_ct_state *ctstate)
 {
        int dir = CTINFO2DIR(ctinfo);
        int ret = 0;
@@ -1589,7 +1668,7 @@ static int process_acf(struct sk_buff *skb, struct 
nf_conn *ct,
        pr_debug("nf_ct_ras: ACF\n");
 
        if (!get_h225_addr(ct, *data, &acf->destCallSignalAddress,
-                          &addr, &port))
+                          &addr, &port, ctstate))
                return 0;
 
        if (!memcmp(&addr, &ct->tuplehash[dir].tuple.dst.u3, sizeof(addr))) {
@@ -1598,7 +1677,8 @@ static int process_acf(struct sk_buff *skb, struct 
nf_conn *ct,
                if (set_sig_addr && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
                    ct->status & IPS_NAT_MASK)
                        return set_sig_addr(skb, ct, ctinfo, protoff, data,
-                                           &acf->destCallSignalAddress, 1);
+                                           &acf->destCallSignalAddress, 1,
+                                           ctstate);
                return 0;
        }
 
@@ -1626,7 +1706,8 @@ static int process_acf(struct sk_buff *skb, struct 
nf_conn *ct,
 static int process_lrq(struct sk_buff *skb, struct nf_conn *ct,
                       enum ip_conntrack_info ctinfo,
                       unsigned int protoff,
-                      unsigned char **data, LocationRequest *lrq)
+                      unsigned char **data, LocationRequest *lrq,
+                      struct h323_ct_state *ctstate)
 {
        typeof(set_ras_addr_hook) set_ras_addr;
 
@@ -1636,7 +1717,8 @@ static int process_lrq(struct sk_buff *skb, struct 
nf_conn *ct,
        if (set_ras_addr && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
            ct->status & IPS_NAT_MASK)
                return set_ras_addr(skb, ct, ctinfo, protoff, data,
-                                   &lrq->replyAddress, 1);
+                                   &lrq->replyAddress, 1,
+                                   ctstate);
        return 0;
 }
 
@@ -1644,7 +1726,8 @@ static int process_lrq(struct sk_buff *skb, struct 
nf_conn *ct,
 static int process_lcf(struct sk_buff *skb, struct nf_conn *ct,
                       enum ip_conntrack_info ctinfo,
                       unsigned int protoff,
-                      unsigned char **data, LocationConfirm *lcf)
+                      unsigned char **data, LocationConfirm *lcf,
+                      struct h323_ct_state *ctstate)
 {
        int dir = CTINFO2DIR(ctinfo);
        int ret = 0;
@@ -1655,7 +1738,7 @@ static int process_lcf(struct sk_buff *skb, struct 
nf_conn *ct,
        pr_debug("nf_ct_ras: LCF\n");
 
        if (!get_h225_addr(ct, *data, &lcf->callSignalAddress,
-                          &addr, &port))
+                          &addr, &port, ctstate))
                return 0;
 
        /* Need new expect for call signal */
@@ -1684,7 +1767,8 @@ static int process_lcf(struct sk_buff *skb, struct 
nf_conn *ct,
 static int process_irr(struct sk_buff *skb, struct nf_conn *ct,
                       enum ip_conntrack_info ctinfo,
                       unsigned int protoff,
-                      unsigned char **data, InfoRequestResponse *irr)
+                      unsigned char **data, InfoRequestResponse *irr,
+                      struct h323_ct_state *ctstate)
 {
        int ret;
        typeof(set_ras_addr_hook) set_ras_addr;
@@ -1696,7 +1780,7 @@ static int process_irr(struct sk_buff *skb, struct 
nf_conn *ct,
        if (set_ras_addr && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
            ct->status & IPS_NAT_MASK) {
                ret = set_ras_addr(skb, ct, ctinfo, protoff, data,
-                                  &irr->rasAddress, 1);
+                                  &irr->rasAddress, 1, ctstate);
                if (ret < 0)
                        return -1;
        }
@@ -1705,8 +1789,9 @@ static int process_irr(struct sk_buff *skb, struct 
nf_conn *ct,
        if (set_sig_addr && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
            ct->status & IPS_NAT_MASK) {
                ret = set_sig_addr(skb, ct, ctinfo, protoff, data,
-                                       irr->callSignalAddress.item,
-                                       irr->callSignalAddress.count);
+                                  irr->callSignalAddress.item,
+                                  irr->callSignalAddress.count,
+                                  ctstate);
                if (ret < 0)
                        return -1;
        }
@@ -1718,39 +1803,40 @@ static int process_irr(struct sk_buff *skb, struct 
nf_conn *ct,
 static int process_ras(struct sk_buff *skb, struct nf_conn *ct,
                       enum ip_conntrack_info ctinfo,
                       unsigned int protoff,
-                      unsigned char **data, RasMessage *ras)
+                      unsigned char **data, RasMessage *ras,
+                      struct h323_ct_state *ctstate)
 {
        switch (ras->choice) {
        case eRasMessage_gatekeeperRequest:
                return process_grq(skb, ct, ctinfo, protoff, data,
-                                  &ras->gatekeeperRequest);
+                                  &ras->gatekeeperRequest, ctstate);
        case eRasMessage_gatekeeperConfirm:
                return process_gcf(skb, ct, ctinfo, protoff, data,
-                                  &ras->gatekeeperConfirm);
+                                  &ras->gatekeeperConfirm, ctstate);
        case eRasMessage_registrationRequest:
                return process_rrq(skb, ct, ctinfo, protoff, data,
-                                  &ras->registrationRequest);
+                                  &ras->registrationRequest, ctstate);
        case eRasMessage_registrationConfirm:
                return process_rcf(skb, ct, ctinfo, protoff, data,
-                                  &ras->registrationConfirm);
+                                  &ras->registrationConfirm, ctstate);
        case eRasMessage_unregistrationRequest:
                return process_urq(skb, ct, ctinfo, protoff, data,
-                                  &ras->unregistrationRequest);
+                                  &ras->unregistrationRequest, ctstate);
        case eRasMessage_admissionRequest:
                return process_arq(skb, ct, ctinfo, protoff, data,
-                                  &ras->admissionRequest);
+                                  &ras->admissionRequest, ctstate);
        case eRasMessage_admissionConfirm:
                return process_acf(skb, ct, ctinfo, protoff, data,
-                                  &ras->admissionConfirm);
+                                  &ras->admissionConfirm, ctstate);
        case eRasMessage_locationRequest:
                return process_lrq(skb, ct, ctinfo, protoff, data,
-                                  &ras->locationRequest);
+                                  &ras->locationRequest, ctstate);
        case eRasMessage_locationConfirm:
                return process_lcf(skb, ct, ctinfo, protoff, data,
-                                  &ras->locationConfirm);
+                                  &ras->locationConfirm, ctstate);
        case eRasMessage_infoRequestResponse:
                return process_irr(skb, ct, ctinfo, protoff, data,
-                                  &ras->infoRequestResponse);
+                                  &ras->infoRequestResponse, ctstate);
        default:
                pr_debug("nf_ct_ras: RAS message %d\n", ras->choice);
                break;
@@ -1767,13 +1853,13 @@ static int ras_help(struct sk_buff *skb, unsigned int 
protoff,
        unsigned char *data;
        int datalen = 0;
        int ret;
+       struct h323_ct_state ctstate = {NULL, NULL, 0};
 
        pr_debug("nf_ct_ras: skblen = %u\n", skb->len);
 
-       spin_lock_bh(&nf_h323_lock);
 
        /* Get UDP data */
-       data = get_udp_data(skb, protoff, &datalen);
+       data = get_udp_data(skb, protoff, &datalen, &ctstate);
        if (data == NULL)
                goto accept;
        pr_debug("nf_ct_ras: RAS message len=%d ", datalen);
@@ -1789,15 +1875,16 @@ static int ras_help(struct sk_buff *skb, unsigned int 
protoff,
        }
 
        /* Process RAS message */
-       if (process_ras(skb, ct, ctinfo, protoff, &data, &ras) < 0)
+       if (process_ras(skb, ct, ctinfo, protoff, &data, &ras,
+                       &ctstate) < 0)
                goto drop;
 
       accept:
-       spin_unlock_bh(&nf_h323_lock);
+       kfree(ctstate.buf);
        return NF_ACCEPT;
 
       drop:
-       spin_unlock_bh(&nf_h323_lock);
+       kfree(ctstate.buf);
        nf_ct_helper_log(skb, ct, "cannot process RAS message");
        return NF_DROP;
 }
@@ -1839,7 +1926,6 @@ static void __exit nf_conntrack_h323_fini(void)
        nf_conntrack_helper_unregister(&nf_conntrack_helper_q931[1]);
        nf_conntrack_helper_unregister(&nf_conntrack_helper_q931[0]);
        nf_conntrack_helper_unregister(&nf_conntrack_helper_h245);
-       kfree(h323_buffer);
        pr_debug("nf_ct_h323: fini\n");
 }
 
@@ -1848,9 +1934,6 @@ static int __init nf_conntrack_h323_init(void)
 {
        int ret;
 
-       h323_buffer = kmalloc(65536, GFP_KERNEL);
-       if (!h323_buffer)
-               return -ENOMEM;
        ret = nf_conntrack_helper_register(&nf_conntrack_helper_h245);
        if (ret < 0)
                goto err1;
@@ -1878,7 +1961,6 @@ err3:
 err2:
        nf_conntrack_helper_unregister(&nf_conntrack_helper_h245);
 err1:
-       kfree(h323_buffer);
        return ret;
 }
 
-- 
2.5.0


Reply via email to